mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 05:23:04 +00:00
vendor: Update vault api package
This commit is contained in:
parent
7ffef62ed7
commit
74dc50a771
15
go.mod
15
go.mod
@ -22,6 +22,7 @@ require (
|
|||||||
github.com/docker/go-connections v0.3.0
|
github.com/docker/go-connections v0.3.0
|
||||||
github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0
|
github.com/elazarl/go-bindata-assetfs v0.0.0-20160803192304-e1a2a7ec64b0
|
||||||
github.com/envoyproxy/go-control-plane v0.9.5
|
github.com/envoyproxy/go-control-plane v0.9.5
|
||||||
|
github.com/go-ldap/ldap v3.0.2+incompatible // indirect
|
||||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
|
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
|
||||||
github.com/golang/protobuf v1.3.5
|
github.com/golang/protobuf v1.3.5
|
||||||
@ -42,6 +43,7 @@ require (
|
|||||||
github.com/hashicorp/go-msgpack v0.5.5
|
github.com/hashicorp/go-msgpack v0.5.5
|
||||||
github.com/hashicorp/go-multierror v1.1.0
|
github.com/hashicorp/go-multierror v1.1.0
|
||||||
github.com/hashicorp/go-raftchunking v0.6.1
|
github.com/hashicorp/go-raftchunking v0.6.1
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.7 // indirect
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2
|
github.com/hashicorp/go-sockaddr v1.0.2
|
||||||
github.com/hashicorp/go-syslog v1.0.0
|
github.com/hashicorp/go-syslog v1.0.0
|
||||||
github.com/hashicorp/go-uuid v1.0.2
|
github.com/hashicorp/go-uuid v1.0.2
|
||||||
@ -54,7 +56,7 @@ require (
|
|||||||
github.com/hashicorp/raft v1.1.2
|
github.com/hashicorp/raft v1.1.2
|
||||||
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea
|
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea
|
||||||
github.com/hashicorp/serf v0.9.4
|
github.com/hashicorp/serf v0.9.4
|
||||||
github.com/hashicorp/vault/api v1.0.4
|
github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d
|
||||||
github.com/imdario/mergo v0.3.6
|
github.com/imdario/mergo v0.3.6
|
||||||
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect
|
github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect
|
||||||
@ -69,6 +71,7 @@ require (
|
|||||||
github.com/mitchellh/pointerstructure v1.0.0
|
github.com/mitchellh/pointerstructure v1.0.0
|
||||||
github.com/mitchellh/reflectwalk v1.0.1
|
github.com/mitchellh/reflectwalk v1.0.1
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
|
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||||
github.com/prometheus/client_golang v1.4.0
|
github.com/prometheus/client_golang v1.4.0
|
||||||
@ -78,18 +81,20 @@ require (
|
|||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
go.opencensus.io v0.22.0 // indirect
|
go.opencensus.io v0.22.0 // indirect
|
||||||
go.uber.org/goleak v1.0.0
|
go.uber.org/goleak v1.0.0
|
||||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
|
golang.org/x/text v0.3.3 // indirect
|
||||||
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e
|
||||||
golang.org/x/tools v0.0.0-20200513154647-78b527d18275 // indirect
|
golang.org/x/tools v0.0.0-20200513154647-78b527d18275 // indirect
|
||||||
google.golang.org/api v0.9.0 // indirect
|
google.golang.org/api v0.9.0 // indirect
|
||||||
google.golang.org/appengine v1.6.0 // indirect
|
google.golang.org/appengine v1.6.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55
|
||||||
google.golang.org/grpc v1.25.1
|
google.golang.org/grpc v1.25.1
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||||
|
gopkg.in/square/go-jose.v2 v2.5.1
|
||||||
k8s.io/api v0.16.9
|
k8s.io/api v0.16.9
|
||||||
k8s.io/apimachinery v0.16.9
|
k8s.io/apimachinery v0.16.9
|
||||||
k8s.io/client-go v0.16.9
|
k8s.io/client-go v0.16.9
|
||||||
|
32
go.sum
32
go.sum
@ -60,11 +60,13 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
|
|||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=
|
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=
|
||||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
||||||
|
github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
|
||||||
github.com/armon/go-metrics v0.3.4 h1:Xqf+7f2Vhl9tsqDYmXhnXInUdcrtgpRNpIA15/uldSc=
|
github.com/armon/go-metrics v0.3.4 h1:Xqf+7f2Vhl9tsqDYmXhnXInUdcrtgpRNpIA15/uldSc=
|
||||||
github.com/armon/go-metrics v0.3.4/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
github.com/armon/go-metrics v0.3.4/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
|
||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.25.41 h1:/hj7nZ0586wFqpwjNpzWiUTwtaMgxAZNZKHay80MdXw=
|
github.com/aws/aws-sdk-go v1.25.41 h1:/hj7nZ0586wFqpwjNpzWiUTwtaMgxAZNZKHay80MdXw=
|
||||||
github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
@ -139,10 +141,12 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-check/check v0.0.0-20140225173054-eb6ee6f84d0a/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
github.com/go-check/check v0.0.0-20140225173054-eb6ee6f84d0a/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
||||||
|
github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
@ -227,6 +231,7 @@ github.com/hashicorp/go-discover v0.0.0-20200501174627-ad1e96bde088/go.mod h1:vZ
|
|||||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
|
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
|
||||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
@ -234,6 +239,7 @@ github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTME
|
|||||||
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
github.com/hashicorp/go-immutable-radix v1.2.0 h1:l6UW37iCXwZkZoAbEYnptSHVE/cQ5bOTPYG5W3vf9+8=
|
github.com/hashicorp/go-immutable-radix v1.2.0 h1:l6UW37iCXwZkZoAbEYnptSHVE/cQ5bOTPYG5W3vf9+8=
|
||||||
github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g=
|
||||||
github.com/hashicorp/go-memdb v1.1.0 h1:ClvpUXpBA6UDs5+vc1h3wqe4UJU+rwum7CU219SeCbk=
|
github.com/hashicorp/go-memdb v1.1.0 h1:ClvpUXpBA6UDs5+vc1h3wqe4UJU+rwum7CU219SeCbk=
|
||||||
github.com/hashicorp/go-memdb v1.1.0/go.mod h1:LWQ8R70vPrS4OEY9k28D2z8/Zzyu34NVzeRibGAzHO0=
|
github.com/hashicorp/go-memdb v1.1.0/go.mod h1:LWQ8R70vPrS4OEY9k28D2z8/Zzyu34NVzeRibGAzHO0=
|
||||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
@ -249,6 +255,10 @@ github.com/hashicorp/go-raftchunking v0.6.1/go.mod h1:cGlg3JtDy7qy6c/3Bu660Mic1J
|
|||||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
|
github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.7 h1:8/CAEZt/+F7kR7GevNHulKkUjLht3CPmn7egmhieNKo=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.7/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
@ -292,8 +302,12 @@ github.com/hashicorp/serf v0.9.4 h1:xrZ4ZR0wT5Dz8oQHHdfOzr0ei1jMToWlFFz3hh/DI7I=
|
|||||||
github.com/hashicorp/serf v0.9.4/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
github.com/hashicorp/serf v0.9.4/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||||
github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=
|
github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=
|
||||||
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
|
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086 h1:OKsyxKi2sNmqm1Gv93adf2AID2FOBFdCbbZn9fGtIdg=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20200717191844-f687267c8086/go.mod h1:R3Umvhlxi2TN7Ex2hzOowyeNb+SfbVWI973N+ctaFMk=
|
||||||
github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8=
|
github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8=
|
||||||
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
|
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
|
||||||
|
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267 h1:e1ok06zGrWJW91rzRroyl5nRNqraaBe4d5hiKcVZuHM=
|
||||||
|
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10=
|
||||||
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw=
|
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw=
|
||||||
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo=
|
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo=
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
@ -374,6 +388,7 @@ github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:
|
|||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
||||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/pointerstructure v1.0.0 h1:ATSdz4NWrmWPOF1CeCBU4sMCno2hgqdbSrRPFWQSVZI=
|
github.com/mitchellh/pointerstructure v1.0.0 h1:ATSdz4NWrmWPOF1CeCBU4sMCno2hgqdbSrRPFWQSVZI=
|
||||||
@ -413,6 +428,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
|
|||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI=
|
||||||
|
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -531,6 +548,7 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
|
|||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
@ -539,6 +557,9 @@ golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947
|
|||||||
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
|
||||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||||
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
@ -571,6 +592,10 @@ golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ym
|
|||||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
||||||
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
|
||||||
|
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
@ -615,6 +640,7 @@ golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSf
|
|||||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -623,11 +649,15 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
|||||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
|
||||||
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
|
||||||
|
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -690,6 +720,8 @@ gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4
|
|||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y=
|
gopkg.in/square/go-jose.v2 v2.4.1 h1:H0TmLt7/KmzlrDOpa1F+zr0Tk90PbJYBfsVUmRLrf9Y=
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
67
vendor/github.com/hashicorp/consul/api/README.md
generated
vendored
Normal file
67
vendor/github.com/hashicorp/consul/api/README.md
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
Consul API client
|
||||||
|
=================
|
||||||
|
|
||||||
|
This package provides the `api` package which attempts to
|
||||||
|
provide programmatic access to the full Consul API.
|
||||||
|
|
||||||
|
Currently, all of the Consul APIs included in version 0.6.0 are supported.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
The full documentation is available on [Godoc](https://godoc.org/github.com/hashicorp/consul/api)
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
Below is an example of using the Consul client:
|
||||||
|
|
||||||
|
```go
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
1363
vendor/github.com/hashicorp/consul/api/acl.go
generated
vendored
Normal file
1363
vendor/github.com/hashicorp/consul/api/acl.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1059
vendor/github.com/hashicorp/consul/api/agent.go
generated
vendored
Normal file
1059
vendor/github.com/hashicorp/consul/api/agent.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1041
vendor/github.com/hashicorp/consul/api/api.go
generated
vendored
Normal file
1041
vendor/github.com/hashicorp/consul/api/api.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
337
vendor/github.com/hashicorp/consul/api/catalog.go
generated
vendored
Normal file
337
vendor/github.com/hashicorp/consul/api/catalog.go
generated
vendored
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Weights struct {
|
||||||
|
Passing int
|
||||||
|
Warning int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
ID string
|
||||||
|
Node string
|
||||||
|
Address string
|
||||||
|
Datacenter string
|
||||||
|
TaggedAddresses map[string]string
|
||||||
|
Meta map[string]string
|
||||||
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceAddress struct {
|
||||||
|
Address string
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
type CatalogService struct {
|
||||||
|
ID string
|
||||||
|
Node string
|
||||||
|
Address string
|
||||||
|
Datacenter string
|
||||||
|
TaggedAddresses map[string]string
|
||||||
|
NodeMeta map[string]string
|
||||||
|
ServiceID string
|
||||||
|
ServiceName string
|
||||||
|
ServiceAddress string
|
||||||
|
ServiceTaggedAddresses map[string]ServiceAddress
|
||||||
|
ServiceTags []string
|
||||||
|
ServiceMeta map[string]string
|
||||||
|
ServicePort int
|
||||||
|
ServiceWeights Weights
|
||||||
|
ServiceEnableTagOverride bool
|
||||||
|
ServiceProxy *AgentServiceConnectProxyConfig
|
||||||
|
CreateIndex uint64
|
||||||
|
Checks HealthChecks
|
||||||
|
ModifyIndex uint64
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CatalogNode struct {
|
||||||
|
Node *Node
|
||||||
|
Services map[string]*AgentService
|
||||||
|
}
|
||||||
|
|
||||||
|
type CatalogNodeServiceList struct {
|
||||||
|
Node *Node
|
||||||
|
Services []*AgentService
|
||||||
|
}
|
||||||
|
|
||||||
|
type CatalogRegistration struct {
|
||||||
|
ID string
|
||||||
|
Node string
|
||||||
|
Address string
|
||||||
|
TaggedAddresses map[string]string
|
||||||
|
NodeMeta map[string]string
|
||||||
|
Datacenter string
|
||||||
|
Service *AgentService
|
||||||
|
Check *AgentCheck
|
||||||
|
Checks HealthChecks
|
||||||
|
SkipNodeUpdate bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type CatalogDeregistration struct {
|
||||||
|
Node string
|
||||||
|
Address string `json:",omitempty"` // Obsolete.
|
||||||
|
Datacenter string
|
||||||
|
ServiceID string
|
||||||
|
CheckID string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CompoundServiceName struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Namespacing is a Consul Enterprise feature.
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GatewayService associates a gateway with a linked service.
|
||||||
|
// It also contains service-specific gateway configuration like ingress listener port and protocol.
|
||||||
|
type GatewayService struct {
|
||||||
|
Gateway CompoundServiceName
|
||||||
|
Service CompoundServiceName
|
||||||
|
GatewayKind ServiceKind
|
||||||
|
Port int `json:",omitempty"`
|
||||||
|
Protocol string `json:",omitempty"`
|
||||||
|
Hosts []string `json:",omitempty"`
|
||||||
|
CAFile string `json:",omitempty"`
|
||||||
|
CertFile string `json:",omitempty"`
|
||||||
|
KeyFile string `json:",omitempty"`
|
||||||
|
SNI string `json:",omitempty"`
|
||||||
|
FromWildcard bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catalog can be used to query the Catalog endpoints
|
||||||
|
type Catalog struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catalog returns a handle to the catalog endpoints
|
||||||
|
func (c *Client) Catalog() *Catalog {
|
||||||
|
return &Catalog{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Catalog) Register(reg *CatalogRegistration, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
r := c.c.newRequest("PUT", "/v1/catalog/register")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = reg
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{}
|
||||||
|
wm.RequestTime = rtt
|
||||||
|
|
||||||
|
return wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Catalog) Deregister(dereg *CatalogDeregistration, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
r := c.c.newRequest("PUT", "/v1/catalog/deregister")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = dereg
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{}
|
||||||
|
wm.RequestTime = rtt
|
||||||
|
|
||||||
|
return wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Datacenters is used to query for all the known datacenters
|
||||||
|
func (c *Catalog) Datacenters() ([]string, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/datacenters")
|
||||||
|
_, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var out []string
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes is used to query all the known nodes
|
||||||
|
func (c *Catalog) Nodes(q *QueryOptions) ([]*Node, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/nodes")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out []*Node
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Services is used to query for all known services
|
||||||
|
func (c *Catalog) Services(q *QueryOptions) (map[string][]string, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/services")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.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][]string
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service is used to query catalog entries for a given service
|
||||||
|
func (c *Catalog) Service(service, tag string, q *QueryOptions) ([]*CatalogService, *QueryMeta, error) {
|
||||||
|
var tags []string
|
||||||
|
if 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 {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out []*CatalogService
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node is used to query for service information about a single node
|
||||||
|
func (c *Catalog) Node(node string, q *QueryOptions) (*CatalogNode, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/node/"+node)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out *CatalogNode
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NodeServiceList is used to query for service information about a single node. It differs from
|
||||||
|
// the Node function only in its return type which will contain a list of services as opposed to
|
||||||
|
// a map of service ids to services. This different structure allows for using the wildcard specifier
|
||||||
|
// '*' for the Namespace in the QueryOptions.
|
||||||
|
func (c *Catalog) NodeServiceList(node string, q *QueryOptions) (*CatalogNodeServiceList, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/node-services/"+node)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out *CatalogNodeServiceList
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GatewayServices is used to query the services associated with an ingress gateway or terminating gateway.
|
||||||
|
func (c *Catalog) GatewayServices(gateway string, q *QueryOptions) ([]*GatewayService, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/catalog/gateway-services/"+gateway)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out []*GatewayService
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseServiceAddr(addrPort string) (ServiceAddress, error) {
|
||||||
|
port := 0
|
||||||
|
host, portStr, err := net.SplitHostPort(addrPort)
|
||||||
|
if err == nil {
|
||||||
|
port, err = strconv.Atoi(portStr)
|
||||||
|
}
|
||||||
|
return ServiceAddress{Address: host, Port: port}, err
|
||||||
|
}
|
353
vendor/github.com/hashicorp/consul/api/config_entry.go
generated
vendored
Normal file
353
vendor/github.com/hashicorp/consul/api/config_entry.go
generated
vendored
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServiceDefaults string = "service-defaults"
|
||||||
|
ProxyDefaults string = "proxy-defaults"
|
||||||
|
ServiceRouter string = "service-router"
|
||||||
|
ServiceSplitter string = "service-splitter"
|
||||||
|
ServiceResolver string = "service-resolver"
|
||||||
|
IngressGateway string = "ingress-gateway"
|
||||||
|
TerminatingGateway string = "terminating-gateway"
|
||||||
|
|
||||||
|
ProxyConfigGlobal string = "global"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigEntry interface {
|
||||||
|
GetKind() string
|
||||||
|
GetName() string
|
||||||
|
GetCreateIndex() uint64
|
||||||
|
GetModifyIndex() uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type MeshGatewayMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MeshGatewayModeDefault represents no specific mode and should
|
||||||
|
// be used to indicate that a different layer of the configuration
|
||||||
|
// chain should take precedence
|
||||||
|
MeshGatewayModeDefault MeshGatewayMode = ""
|
||||||
|
|
||||||
|
// MeshGatewayModeNone represents that the Upstream Connect connections
|
||||||
|
// should be direct and not flow through a mesh gateway.
|
||||||
|
MeshGatewayModeNone MeshGatewayMode = "none"
|
||||||
|
|
||||||
|
// MeshGatewayModeLocal represents that the Upstrea Connect connections
|
||||||
|
// should be made to a mesh gateway in the local datacenter. This is
|
||||||
|
MeshGatewayModeLocal MeshGatewayMode = "local"
|
||||||
|
|
||||||
|
// MeshGatewayModeRemote represents that the Upstream Connect connections
|
||||||
|
// should be made to a mesh gateway in a remote datacenter.
|
||||||
|
MeshGatewayModeRemote MeshGatewayMode = "remote"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MeshGatewayConfig controls how Mesh Gateways are used for upstream Connect
|
||||||
|
// services
|
||||||
|
type MeshGatewayConfig struct {
|
||||||
|
// Mode is the mode that should be used for the upstream connection.
|
||||||
|
Mode MeshGatewayMode `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExposeConfig describes HTTP paths to expose through Envoy outside of Connect.
|
||||||
|
// Users can expose individual paths and/or all HTTP/GRPC paths for checks.
|
||||||
|
type ExposeConfig struct {
|
||||||
|
// Checks defines whether paths associated with Consul checks will be exposed.
|
||||||
|
// This flag triggers exposing all HTTP and GRPC check paths registered for the service.
|
||||||
|
Checks bool `json:",omitempty"`
|
||||||
|
|
||||||
|
// Paths is the list of paths exposed through the proxy.
|
||||||
|
Paths []ExposePath `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExposePath struct {
|
||||||
|
// ListenerPort defines the port of the proxy's listener for exposed paths.
|
||||||
|
ListenerPort int `json:",omitempty" alias:"listener_port"`
|
||||||
|
|
||||||
|
// Path is the path to expose through the proxy, ie. "/metrics."
|
||||||
|
Path string `json:",omitempty"`
|
||||||
|
|
||||||
|
// LocalPathPort is the port that the service is listening on for the given path.
|
||||||
|
LocalPathPort int `json:",omitempty" alias:"local_path_port"`
|
||||||
|
|
||||||
|
// Protocol describes the upstream's service protocol.
|
||||||
|
// Valid values are "http" and "http2", defaults to "http"
|
||||||
|
Protocol string `json:",omitempty"`
|
||||||
|
|
||||||
|
// ParsedFromCheck is set if this path was parsed from a registered check
|
||||||
|
ParsedFromCheck bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceConfigEntry struct {
|
||||||
|
Kind string
|
||||||
|
Name string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
Protocol string `json:",omitempty"`
|
||||||
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||||
|
Expose ExposeConfig `json:",omitempty"`
|
||||||
|
ExternalSNI string `json:",omitempty" alias:"external_sni"`
|
||||||
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceConfigEntry) GetKind() string {
|
||||||
|
return s.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceConfigEntry) GetName() string {
|
||||||
|
return s.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceConfigEntry) GetCreateIndex() uint64 {
|
||||||
|
return s.CreateIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ServiceConfigEntry) GetModifyIndex() uint64 {
|
||||||
|
return s.ModifyIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProxyConfigEntry struct {
|
||||||
|
Kind string
|
||||||
|
Name string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
Config map[string]interface{} `json:",omitempty"`
|
||||||
|
MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"`
|
||||||
|
Expose ExposeConfig `json:",omitempty"`
|
||||||
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyConfigEntry) GetKind() string {
|
||||||
|
return p.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyConfigEntry) GetName() string {
|
||||||
|
return p.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyConfigEntry) GetCreateIndex() uint64 {
|
||||||
|
return p.CreateIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyConfigEntry) GetModifyIndex() uint64 {
|
||||||
|
return p.ModifyIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeConfigEntry(kind, name string) (ConfigEntry, error) {
|
||||||
|
switch kind {
|
||||||
|
case ServiceDefaults:
|
||||||
|
return &ServiceConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
case ProxyDefaults:
|
||||||
|
return &ProxyConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
case ServiceRouter:
|
||||||
|
return &ServiceRouterConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
case ServiceSplitter:
|
||||||
|
return &ServiceSplitterConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
case ServiceResolver:
|
||||||
|
return &ServiceResolverConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
case IngressGateway:
|
||||||
|
return &IngressGatewayConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
case TerminatingGateway:
|
||||||
|
return &TerminatingGatewayConfigEntry{Kind: kind, Name: name}, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid config entry kind: %s", kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeConfigEntry(kind, name string) (ConfigEntry, error) {
|
||||||
|
return makeConfigEntry(kind, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeConfigEntry will decode the result of using json.Unmarshal of a config
|
||||||
|
// entry into a map[string]interface{}.
|
||||||
|
//
|
||||||
|
// Important caveats:
|
||||||
|
//
|
||||||
|
// - This will NOT work if the map[string]interface{} was produced using HCL
|
||||||
|
// decoding as that requires more extensive parsing to work around the issues
|
||||||
|
// with map[string][]interface{} that arise.
|
||||||
|
//
|
||||||
|
// - This will only decode fields using their camel case json field
|
||||||
|
// representations.
|
||||||
|
func DecodeConfigEntry(raw map[string]interface{}) (ConfigEntry, error) {
|
||||||
|
var entry ConfigEntry
|
||||||
|
|
||||||
|
kindVal, ok := raw["Kind"]
|
||||||
|
if !ok {
|
||||||
|
kindVal, ok = raw["kind"]
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Payload does not contain a kind/Kind key at the top level")
|
||||||
|
}
|
||||||
|
|
||||||
|
if kindStr, ok := kindVal.(string); ok {
|
||||||
|
newEntry, err := makeConfigEntry(kindStr, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entry = newEntry
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("Kind value in payload is not a string")
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeConf := &mapstructure.DecoderConfig{
|
||||||
|
DecodeHook: mapstructure.StringToTimeDurationHookFunc(),
|
||||||
|
Result: &entry,
|
||||||
|
WeaklyTypedInput: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := mapstructure.NewDecoder(decodeConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry, decoder.Decode(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeConfigEntryFromJSON(data []byte) (ConfigEntry, error) {
|
||||||
|
var raw map[string]interface{}
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecodeConfigEntry(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeConfigEntrySlice(raw []map[string]interface{}) ([]ConfigEntry, error) {
|
||||||
|
var entries []ConfigEntry
|
||||||
|
for _, rawEntry := range raw {
|
||||||
|
entry, err := DecodeConfigEntry(rawEntry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigEntries can be used to query the Config endpoints
|
||||||
|
type ConfigEntries struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns a handle to the Config endpoints
|
||||||
|
func (c *Client) ConfigEntries() *ConfigEntries {
|
||||||
|
return &ConfigEntries{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *ConfigEntries) Get(kind string, name string, q *QueryOptions) (ConfigEntry, *QueryMeta, error) {
|
||||||
|
if kind == "" || name == "" {
|
||||||
|
return nil, nil, fmt.Errorf("Both kind and name parameters must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
entry, err := makeConfigEntry(kind, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r := conf.c.newRequest("GET", fmt.Sprintf("/v1/config/%s/%s", kind, name))
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(conf.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
if err := decodeBody(resp, entry); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *ConfigEntries) List(kind string, q *QueryOptions) ([]ConfigEntry, *QueryMeta, error) {
|
||||||
|
if kind == "" {
|
||||||
|
return nil, nil, fmt.Errorf("The kind parameter must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := conf.c.newRequest("GET", fmt.Sprintf("/v1/config/%s", kind))
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(conf.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var raw []map[string]interface{}
|
||||||
|
if err := decodeBody(resp, &raw); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := decodeConfigEntrySlice(raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *ConfigEntries) Set(entry ConfigEntry, w *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
return conf.set(entry, nil, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *ConfigEntries) CAS(entry ConfigEntry, index uint64, w *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
return conf.set(entry, map[string]string{"cas": strconv.FormatUint(index, 10)}, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *ConfigEntries) set(entry ConfigEntry, params map[string]string, w *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
r := conf.c.newRequest("PUT", "/v1/config")
|
||||||
|
r.setWriteOptions(w)
|
||||||
|
for param, value := range params {
|
||||||
|
r.params.Set(param, value)
|
||||||
|
}
|
||||||
|
r.obj = entry
|
||||||
|
rtt, resp, err := requireOK(conf.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return false, nil, fmt.Errorf("Failed to read response: %v", err)
|
||||||
|
}
|
||||||
|
res := strings.Contains(buf.String(), "true")
|
||||||
|
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
return res, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *ConfigEntries) Delete(kind string, name string, w *WriteOptions) (*WriteMeta, error) {
|
||||||
|
if kind == "" || name == "" {
|
||||||
|
return nil, fmt.Errorf("Both kind and name parameters must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := conf.c.newRequest("DELETE", fmt.Sprintf("/v1/config/%s/%s", kind, name))
|
||||||
|
r.setWriteOptions(w)
|
||||||
|
rtt, resp, err := requireOK(conf.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
return wm, nil
|
||||||
|
}
|
203
vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go
generated
vendored
Normal file
203
vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceRouterConfigEntry struct {
|
||||||
|
Kind string
|
||||||
|
Name string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
Routes []ServiceRoute `json:",omitempty"`
|
||||||
|
|
||||||
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceRouterConfigEntry) GetKind() string { return e.Kind }
|
||||||
|
func (e *ServiceRouterConfigEntry) GetName() string { return e.Name }
|
||||||
|
func (e *ServiceRouterConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex }
|
||||||
|
func (e *ServiceRouterConfigEntry) GetModifyIndex() uint64 { return e.ModifyIndex }
|
||||||
|
|
||||||
|
type ServiceRoute struct {
|
||||||
|
Match *ServiceRouteMatch `json:",omitempty"`
|
||||||
|
Destination *ServiceRouteDestination `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceRouteMatch struct {
|
||||||
|
HTTP *ServiceRouteHTTPMatch `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceRouteHTTPMatch struct {
|
||||||
|
PathExact string `json:",omitempty" alias:"path_exact"`
|
||||||
|
PathPrefix string `json:",omitempty" alias:"path_prefix"`
|
||||||
|
PathRegex string `json:",omitempty" alias:"path_regex"`
|
||||||
|
|
||||||
|
Header []ServiceRouteHTTPMatchHeader `json:",omitempty"`
|
||||||
|
QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty" alias:"query_param"`
|
||||||
|
Methods []string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceRouteHTTPMatchHeader struct {
|
||||||
|
Name string
|
||||||
|
Present bool `json:",omitempty"`
|
||||||
|
Exact string `json:",omitempty"`
|
||||||
|
Prefix string `json:",omitempty"`
|
||||||
|
Suffix string `json:",omitempty"`
|
||||||
|
Regex string `json:",omitempty"`
|
||||||
|
Invert bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceRouteHTTPMatchQueryParam struct {
|
||||||
|
Name string
|
||||||
|
Present bool `json:",omitempty"`
|
||||||
|
Exact string `json:",omitempty"`
|
||||||
|
Regex string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceRouteDestination struct {
|
||||||
|
Service string `json:",omitempty"`
|
||||||
|
ServiceSubset string `json:",omitempty" alias:"service_subset"`
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
PrefixRewrite string `json:",omitempty" alias:"prefix_rewrite"`
|
||||||
|
RequestTimeout time.Duration `json:",omitempty" alias:"request_timeout"`
|
||||||
|
NumRetries uint32 `json:",omitempty" alias:"num_retries"`
|
||||||
|
RetryOnConnectFailure bool `json:",omitempty" alias:"retry_on_connect_failure"`
|
||||||
|
RetryOnStatusCodes []uint32 `json:",omitempty" alias:"retry_on_status_codes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceRouteDestination) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias ServiceRouteDestination
|
||||||
|
exported := &struct {
|
||||||
|
RequestTimeout string `json:",omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
RequestTimeout: e.RequestTimeout.String(),
|
||||||
|
Alias: (*Alias)(e),
|
||||||
|
}
|
||||||
|
if e.RequestTimeout == 0 {
|
||||||
|
exported.RequestTimeout = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(exported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceRouteDestination) UnmarshalJSON(data []byte) error {
|
||||||
|
type Alias ServiceRouteDestination
|
||||||
|
aux := &struct {
|
||||||
|
RequestTimeout string
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(e),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if aux.RequestTimeout != "" {
|
||||||
|
if e.RequestTimeout, err = time.ParseDuration(aux.RequestTimeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceSplitterConfigEntry struct {
|
||||||
|
Kind string
|
||||||
|
Name string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
Splits []ServiceSplit `json:",omitempty"`
|
||||||
|
|
||||||
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceSplitterConfigEntry) GetKind() string { return e.Kind }
|
||||||
|
func (e *ServiceSplitterConfigEntry) GetName() string { return e.Name }
|
||||||
|
func (e *ServiceSplitterConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex }
|
||||||
|
func (e *ServiceSplitterConfigEntry) GetModifyIndex() uint64 { return e.ModifyIndex }
|
||||||
|
|
||||||
|
type ServiceSplit struct {
|
||||||
|
Weight float32
|
||||||
|
Service string `json:",omitempty"`
|
||||||
|
ServiceSubset string `json:",omitempty" alias:"service_subset"`
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceResolverConfigEntry struct {
|
||||||
|
Kind string
|
||||||
|
Name string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
DefaultSubset string `json:",omitempty" alias:"default_subset"`
|
||||||
|
Subsets map[string]ServiceResolverSubset `json:",omitempty"`
|
||||||
|
Redirect *ServiceResolverRedirect `json:",omitempty"`
|
||||||
|
Failover map[string]ServiceResolverFailover `json:",omitempty"`
|
||||||
|
ConnectTimeout time.Duration `json:",omitempty" alias:"connect_timeout"`
|
||||||
|
|
||||||
|
CreateIndex uint64
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceResolverConfigEntry) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias ServiceResolverConfigEntry
|
||||||
|
exported := &struct {
|
||||||
|
ConnectTimeout string `json:",omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
ConnectTimeout: e.ConnectTimeout.String(),
|
||||||
|
Alias: (*Alias)(e),
|
||||||
|
}
|
||||||
|
if e.ConnectTimeout == 0 {
|
||||||
|
exported.ConnectTimeout = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(exported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceResolverConfigEntry) UnmarshalJSON(data []byte) error {
|
||||||
|
type Alias ServiceResolverConfigEntry
|
||||||
|
aux := &struct {
|
||||||
|
ConnectTimeout string
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(e),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if aux.ConnectTimeout != "" {
|
||||||
|
if e.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ServiceResolverConfigEntry) GetKind() string { return e.Kind }
|
||||||
|
func (e *ServiceResolverConfigEntry) GetName() string { return e.Name }
|
||||||
|
func (e *ServiceResolverConfigEntry) GetCreateIndex() uint64 { return e.CreateIndex }
|
||||||
|
func (e *ServiceResolverConfigEntry) GetModifyIndex() uint64 { return e.ModifyIndex }
|
||||||
|
|
||||||
|
type ServiceResolverSubset struct {
|
||||||
|
Filter string `json:",omitempty"`
|
||||||
|
OnlyPassing bool `json:",omitempty" alias:"only_passing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceResolverRedirect struct {
|
||||||
|
Service string `json:",omitempty"`
|
||||||
|
ServiceSubset string `json:",omitempty" alias:"service_subset"`
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
Datacenter string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceResolverFailover struct {
|
||||||
|
Service string `json:",omitempty"`
|
||||||
|
ServiceSubset string `json:",omitempty" alias:"service_subset"`
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
Datacenters []string `json:",omitempty"`
|
||||||
|
}
|
170
vendor/github.com/hashicorp/consul/api/config_entry_gateways.go
generated
vendored
Normal file
170
vendor/github.com/hashicorp/consul/api/config_entry_gateways.go
generated
vendored
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// IngressGatewayConfigEntry manages the configuration for an ingress service
|
||||||
|
// with the given name.
|
||||||
|
type IngressGatewayConfigEntry struct {
|
||||||
|
// Kind of the config entry. This should be set to api.IngressGateway.
|
||||||
|
Kind string
|
||||||
|
|
||||||
|
// Name is used to match the config entry with its associated ingress gateway
|
||||||
|
// service. This should match the name provided in the service definition.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Namespace is the namespace the IngressGateway is associated with
|
||||||
|
// Namespacing is a Consul Enterprise feature.
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
// TLS holds the TLS configuration for this gateway.
|
||||||
|
TLS GatewayTLSConfig
|
||||||
|
|
||||||
|
// Listeners declares what ports the ingress gateway should listen on, and
|
||||||
|
// what services to associated to those ports.
|
||||||
|
Listeners []IngressListener
|
||||||
|
|
||||||
|
// CreateIndex is the Raft index this entry was created at. This is a
|
||||||
|
// read-only field.
|
||||||
|
CreateIndex uint64
|
||||||
|
|
||||||
|
// ModifyIndex is used for the Check-And-Set operations and can also be fed
|
||||||
|
// back into the WaitIndex of the QueryOptions in order to perform blocking
|
||||||
|
// queries.
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayTLSConfig struct {
|
||||||
|
// Indicates that TLS should be enabled for this gateway service
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IngressListener manages the configuration for a listener on a specific port.
|
||||||
|
type IngressListener struct {
|
||||||
|
// Port declares the port on which the ingress gateway should listen for traffic.
|
||||||
|
Port int
|
||||||
|
|
||||||
|
// Protocol declares what type of traffic this listener is expected to
|
||||||
|
// receive. Depending on the protocol, a listener might support multiplexing
|
||||||
|
// services over a single port, or additional discovery chain features. The
|
||||||
|
// current supported values are: (tcp | http).
|
||||||
|
Protocol string
|
||||||
|
|
||||||
|
// Services declares the set of services to which the listener forwards
|
||||||
|
// traffic.
|
||||||
|
//
|
||||||
|
// For "tcp" protocol listeners, only a single service is allowed.
|
||||||
|
// For "http" listeners, multiple services can be declared.
|
||||||
|
Services []IngressService
|
||||||
|
}
|
||||||
|
|
||||||
|
// IngressService manages configuration for services that are exposed to
|
||||||
|
// ingress traffic.
|
||||||
|
type IngressService struct {
|
||||||
|
// Name declares the service to which traffic should be forwarded.
|
||||||
|
//
|
||||||
|
// This can either be a specific service, or the wildcard specifier,
|
||||||
|
// "*". If the wildcard specifier is provided, the listener must be of "http"
|
||||||
|
// protocol and means that the listener will forward traffic to all services.
|
||||||
|
//
|
||||||
|
// A name can be specified on multiple listeners, and will be exposed on both
|
||||||
|
// of the listeners
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Hosts is a list of hostnames which should be associated to this service on
|
||||||
|
// the defined listener. Only allowed on layer 7 protocols, this will be used
|
||||||
|
// to route traffic to the service by matching the Host header of the HTTP
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// If a host is provided for a service that also has a wildcard specifier
|
||||||
|
// defined, the host will override the wildcard-specifier-provided
|
||||||
|
// "<service-name>.*" domain for that listener.
|
||||||
|
//
|
||||||
|
// This cannot be specified when using the wildcard specifier, "*", or when
|
||||||
|
// using a "tcp" listener.
|
||||||
|
Hosts []string
|
||||||
|
|
||||||
|
// Namespace is the namespace where the service is located.
|
||||||
|
// Namespacing is a Consul Enterprise feature.
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IngressGatewayConfigEntry) GetKind() string {
|
||||||
|
return i.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IngressGatewayConfigEntry) GetName() string {
|
||||||
|
return i.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IngressGatewayConfigEntry) GetCreateIndex() uint64 {
|
||||||
|
return i.CreateIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IngressGatewayConfigEntry) GetModifyIndex() uint64 {
|
||||||
|
return i.ModifyIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
// TerminatingGatewayConfigEntry manages the configuration for a terminating gateway
|
||||||
|
// with the given name.
|
||||||
|
type TerminatingGatewayConfigEntry struct {
|
||||||
|
// Kind of the config entry. This should be set to api.TerminatingGateway.
|
||||||
|
Kind string
|
||||||
|
|
||||||
|
// Name is used to match the config entry with its associated terminating gateway
|
||||||
|
// service. This should match the name provided in the service definition.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Services is a list of service names represented by the terminating gateway.
|
||||||
|
Services []LinkedService `json:",omitempty"`
|
||||||
|
|
||||||
|
// CreateIndex is the Raft index this entry was created at. This is a
|
||||||
|
// read-only field.
|
||||||
|
CreateIndex uint64
|
||||||
|
|
||||||
|
// ModifyIndex is used for the Check-And-Set operations and can also be fed
|
||||||
|
// back into the WaitIndex of the QueryOptions in order to perform blocking
|
||||||
|
// queries.
|
||||||
|
ModifyIndex uint64
|
||||||
|
|
||||||
|
// Namespace is the namespace the config entry is associated with
|
||||||
|
// Namespacing is a Consul Enterprise feature.
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// A LinkedService is a service represented by a terminating gateway
|
||||||
|
type LinkedService struct {
|
||||||
|
// The namespace the service is registered in
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
// Name is the name of the service, as defined in Consul's catalog
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
|
||||||
|
// CAFile is the optional path to a CA certificate to use for TLS connections
|
||||||
|
// from the gateway to the linked service
|
||||||
|
CAFile string `json:",omitempty" alias:"ca_file"`
|
||||||
|
|
||||||
|
// CertFile is the optional path to a client certificate to use for TLS connections
|
||||||
|
// from the gateway to the linked service
|
||||||
|
CertFile string `json:",omitempty" alias:"cert_file"`
|
||||||
|
|
||||||
|
// KeyFile is the optional path to a private key to use for TLS connections
|
||||||
|
// from the gateway to the linked service
|
||||||
|
KeyFile string `json:",omitempty" alias:"key_file"`
|
||||||
|
|
||||||
|
// SNI is the optional name to specify during the TLS handshake with a linked service
|
||||||
|
SNI string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *TerminatingGatewayConfigEntry) GetKind() string {
|
||||||
|
return g.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *TerminatingGatewayConfigEntry) GetName() string {
|
||||||
|
return g.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *TerminatingGatewayConfigEntry) GetCreateIndex() uint64 {
|
||||||
|
return g.CreateIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *TerminatingGatewayConfigEntry) GetModifyIndex() uint64 {
|
||||||
|
return g.ModifyIndex
|
||||||
|
}
|
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}
|
||||||
|
}
|
181
vendor/github.com/hashicorp/consul/api/connect_ca.go
generated
vendored
Normal file
181
vendor/github.com/hashicorp/consul/api/connect_ca.go
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
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{}
|
||||||
|
|
||||||
|
// State is read-only data that the provider might have persisted for use
|
||||||
|
// after restart or leadership transition. For example this might include
|
||||||
|
// UUIDs of resources it has created. Setting this when writing a
|
||||||
|
// configuration is an error.
|
||||||
|
State map[string]string
|
||||||
|
|
||||||
|
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
|
||||||
|
IntermediateCertTTL 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
|
||||||
|
}
|
344
vendor/github.com/hashicorp/consul/api/connect_intention.go
generated
vendored
Normal file
344
vendor/github.com/hashicorp/consul/api/connect_intention.go
generated
vendored
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
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 an allowlist or denylist intention.
|
||||||
|
Action IntentionAction
|
||||||
|
|
||||||
|
// DefaultAddr is not used.
|
||||||
|
// Deprecated: DefaultAddr is not used and may be removed in a future version.
|
||||||
|
DefaultAddr string `json:",omitempty"`
|
||||||
|
// DefaultPort is not used.
|
||||||
|
// Deprecated: DefaultPort is not used and may be removed in a future version.
|
||||||
|
DefaultPort int `json:",omitempty"`
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// Hash of the contents of the intention
|
||||||
|
//
|
||||||
|
// This is needed mainly for replication purposes. When replicating from
|
||||||
|
// one DC to another keeping the content Hash will allow us to detect
|
||||||
|
// content changes more efficiently than checking every single field
|
||||||
|
Hash []byte
|
||||||
|
|
||||||
|
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 allowlist or denylist 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntentionGetExact retrieves a single intention by its unique name instead of
|
||||||
|
// its ID.
|
||||||
|
func (h *Connect) IntentionGetExact(source, destination string, q *QueryOptions) (*Intention, *QueryMeta, error) {
|
||||||
|
r := h.c.newRequest("GET", "/v1/connect/intentions/exact")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
r.params.Set("source", source)
|
||||||
|
r.params.Set("destination", destination)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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/coordinate.go
generated
vendored
Normal file
106
vendor/github.com/hashicorp/consul/api/coordinate.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/serf/coordinate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CoordinateEntry represents a node and its associated network coordinate.
|
||||||
|
type CoordinateEntry struct {
|
||||||
|
Node string
|
||||||
|
Segment string
|
||||||
|
Coord *coordinate.Coordinate
|
||||||
|
}
|
||||||
|
|
||||||
|
// CoordinateDatacenterMap has the coordinates for servers in a given datacenter
|
||||||
|
// and area. Network coordinates are only compatible within the same area.
|
||||||
|
type CoordinateDatacenterMap struct {
|
||||||
|
Datacenter string
|
||||||
|
AreaID string
|
||||||
|
Coordinates []CoordinateEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coordinate can be used to query the coordinate endpoints
|
||||||
|
type Coordinate struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coordinate returns a handle to the coordinate endpoints
|
||||||
|
func (c *Client) Coordinate() *Coordinate {
|
||||||
|
return &Coordinate{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Datacenters is used to return the coordinates of all the servers in the WAN
|
||||||
|
// pool.
|
||||||
|
func (c *Coordinate) Datacenters() ([]*CoordinateDatacenterMap, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/coordinate/datacenters")
|
||||||
|
_, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var out []*CoordinateDatacenterMap
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes is used to return the coordinates of all the nodes in the LAN pool.
|
||||||
|
func (c *Coordinate) Nodes(q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/coordinate/nodes")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out []*CoordinateEntry
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update inserts or updates the LAN coordinate of a node.
|
||||||
|
func (c *Coordinate) Update(coord *CoordinateEntry, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
r := c.c.newRequest("PUT", "/v1/coordinate/update")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = coord
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node is used to return the coordinates of a single node in the LAN pool.
|
||||||
|
func (c *Coordinate) Node(node string, q *QueryOptions) ([]*CoordinateEntry, *QueryMeta, error) {
|
||||||
|
r := c.c.newRequest("GET", "/v1/coordinate/node/"+node)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(c.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out []*CoordinateEntry
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, 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
|
||||||
|
}
|
229
vendor/github.com/hashicorp/consul/api/discovery_chain.go
generated
vendored
Normal file
229
vendor/github.com/hashicorp/consul/api/discovery_chain.go
generated
vendored
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiscoveryChain can be used to query the discovery-chain endpoints
|
||||||
|
type DiscoveryChain struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoveryChain returns a handle to the discovery-chain endpoints
|
||||||
|
func (c *Client) DiscoveryChain() *DiscoveryChain {
|
||||||
|
return &DiscoveryChain{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DiscoveryChain) Get(name string, opts *DiscoveryChainOptions, q *QueryOptions) (*DiscoveryChainResponse, *QueryMeta, error) {
|
||||||
|
if name == "" {
|
||||||
|
return nil, nil, fmt.Errorf("Name parameter must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
method := "GET"
|
||||||
|
if opts != nil && opts.requiresPOST() {
|
||||||
|
method = "POST"
|
||||||
|
}
|
||||||
|
|
||||||
|
r := d.c.newRequest(method, fmt.Sprintf("/v1/discovery-chain/%s", name))
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
|
||||||
|
if opts != nil {
|
||||||
|
if opts.EvaluateInDatacenter != "" {
|
||||||
|
r.params.Set("compile-dc", opts.EvaluateInDatacenter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if method == "POST" {
|
||||||
|
r.obj = opts
|
||||||
|
}
|
||||||
|
|
||||||
|
rtt, resp, err := requireOK(d.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out DiscoveryChainResponse
|
||||||
|
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiscoveryChainOptions struct {
|
||||||
|
EvaluateInDatacenter string `json:"-"`
|
||||||
|
|
||||||
|
// OverrideMeshGateway allows for the mesh gateway setting to be overridden
|
||||||
|
// for any resolver in the compiled chain.
|
||||||
|
OverrideMeshGateway MeshGatewayConfig `json:",omitempty"`
|
||||||
|
|
||||||
|
// OverrideProtocol allows for the final protocol for the chain to be
|
||||||
|
// altered.
|
||||||
|
//
|
||||||
|
// - If the chain ordinarily would be TCP and an L7 protocol is passed here
|
||||||
|
// the chain will not include Routers or Splitters.
|
||||||
|
//
|
||||||
|
// - If the chain ordinarily would be L7 and TCP is passed here the chain
|
||||||
|
// will not include Routers or Splitters.
|
||||||
|
OverrideProtocol string `json:",omitempty"`
|
||||||
|
|
||||||
|
// OverrideConnectTimeout allows for the ConnectTimeout setting to be
|
||||||
|
// overridden for any resolver in the compiled chain.
|
||||||
|
OverrideConnectTimeout time.Duration `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *DiscoveryChainOptions) requiresPOST() bool {
|
||||||
|
if o == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return o.OverrideMeshGateway.Mode != "" ||
|
||||||
|
o.OverrideProtocol != "" ||
|
||||||
|
o.OverrideConnectTimeout != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiscoveryChainResponse struct {
|
||||||
|
Chain *CompiledDiscoveryChain
|
||||||
|
}
|
||||||
|
|
||||||
|
type CompiledDiscoveryChain struct {
|
||||||
|
ServiceName string
|
||||||
|
Namespace string
|
||||||
|
Datacenter string
|
||||||
|
|
||||||
|
// CustomizationHash is a unique hash of any data that affects the
|
||||||
|
// compilation of the discovery chain other than config entries or the
|
||||||
|
// name/namespace/datacenter evaluation criteria.
|
||||||
|
//
|
||||||
|
// If set, this value should be used to prefix/suffix any generated load
|
||||||
|
// balancer data plane objects to avoid sharing customized and
|
||||||
|
// non-customized versions.
|
||||||
|
CustomizationHash string
|
||||||
|
|
||||||
|
// Protocol is the overall protocol shared by everything in the chain.
|
||||||
|
Protocol string
|
||||||
|
|
||||||
|
// StartNode is the first key into the Nodes map that should be followed
|
||||||
|
// when walking the discovery chain.
|
||||||
|
StartNode string
|
||||||
|
|
||||||
|
// Nodes contains all nodes available for traversal in the chain keyed by a
|
||||||
|
// unique name. You can walk this by starting with StartNode.
|
||||||
|
//
|
||||||
|
// NOTE: The names should be treated as opaque values and are only
|
||||||
|
// guaranteed to be consistent within a single compilation.
|
||||||
|
Nodes map[string]*DiscoveryGraphNode
|
||||||
|
|
||||||
|
// Targets is a list of all targets used in this chain.
|
||||||
|
//
|
||||||
|
// NOTE: The names should be treated as opaque values and are only
|
||||||
|
// guaranteed to be consistent within a single compilation.
|
||||||
|
Targets map[string]*DiscoveryTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DiscoveryGraphNodeTypeRouter = "router"
|
||||||
|
DiscoveryGraphNodeTypeSplitter = "splitter"
|
||||||
|
DiscoveryGraphNodeTypeResolver = "resolver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiscoveryGraphNode is a single node in the compiled discovery chain.
|
||||||
|
type DiscoveryGraphNode struct {
|
||||||
|
Type string
|
||||||
|
Name string // this is NOT necessarily a service
|
||||||
|
|
||||||
|
// fields for Type==router
|
||||||
|
Routes []*DiscoveryRoute
|
||||||
|
|
||||||
|
// fields for Type==splitter
|
||||||
|
Splits []*DiscoverySplit
|
||||||
|
|
||||||
|
// fields for Type==resolver
|
||||||
|
Resolver *DiscoveryResolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// compiled form of ServiceRoute
|
||||||
|
type DiscoveryRoute struct {
|
||||||
|
Definition *ServiceRoute
|
||||||
|
NextNode string
|
||||||
|
}
|
||||||
|
|
||||||
|
// compiled form of ServiceSplit
|
||||||
|
type DiscoverySplit struct {
|
||||||
|
Weight float32
|
||||||
|
NextNode string
|
||||||
|
}
|
||||||
|
|
||||||
|
// compiled form of ServiceResolverConfigEntry
|
||||||
|
type DiscoveryResolver struct {
|
||||||
|
Default bool
|
||||||
|
ConnectTimeout time.Duration
|
||||||
|
Target string
|
||||||
|
Failover *DiscoveryFailover
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DiscoveryResolver) MarshalJSON() ([]byte, error) {
|
||||||
|
type Alias DiscoveryResolver
|
||||||
|
exported := &struct {
|
||||||
|
ConnectTimeout string `json:",omitempty"`
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
ConnectTimeout: r.ConnectTimeout.String(),
|
||||||
|
Alias: (*Alias)(r),
|
||||||
|
}
|
||||||
|
if r.ConnectTimeout == 0 {
|
||||||
|
exported.ConnectTimeout = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(exported)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DiscoveryResolver) UnmarshalJSON(data []byte) error {
|
||||||
|
type Alias DiscoveryResolver
|
||||||
|
aux := &struct {
|
||||||
|
ConnectTimeout string
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(r),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if aux.ConnectTimeout != "" {
|
||||||
|
if r.ConnectTimeout, err = time.ParseDuration(aux.ConnectTimeout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// compiled form of ServiceResolverFailover
|
||||||
|
type DiscoveryFailover struct {
|
||||||
|
Targets []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoveryTarget represents all of the inputs necessary to use a resolver
|
||||||
|
// config entry to execute a catalog query to generate a list of service
|
||||||
|
// instances during discovery.
|
||||||
|
type DiscoveryTarget struct {
|
||||||
|
ID string
|
||||||
|
|
||||||
|
Service string
|
||||||
|
ServiceSubset string
|
||||||
|
Namespace string
|
||||||
|
Datacenter string
|
||||||
|
|
||||||
|
MeshGateway MeshGatewayConfig
|
||||||
|
Subset ServiceResolverSubset
|
||||||
|
External bool
|
||||||
|
SNI string
|
||||||
|
Name string
|
||||||
|
}
|
104
vendor/github.com/hashicorp/consul/api/event.go
generated
vendored
Normal file
104
vendor/github.com/hashicorp/consul/api/event.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Event can be used to query the Event endpoints
|
||||||
|
type Event struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserEvent represents an event that was fired by the user
|
||||||
|
type UserEvent struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Payload []byte
|
||||||
|
NodeFilter string
|
||||||
|
ServiceFilter string
|
||||||
|
TagFilter string
|
||||||
|
Version int
|
||||||
|
LTime uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event returns a handle to the event endpoints
|
||||||
|
func (c *Client) Event() *Event {
|
||||||
|
return &Event{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire is used to fire a new user event. Only the Name, Payload and Filters
|
||||||
|
// are respected. This returns the ID or an associated error. Cross DC requests
|
||||||
|
// are supported.
|
||||||
|
func (e *Event) Fire(params *UserEvent, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
r := e.c.newRequest("PUT", "/v1/event/fire/"+params.Name)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
if params.NodeFilter != "" {
|
||||||
|
r.params.Set("node", params.NodeFilter)
|
||||||
|
}
|
||||||
|
if params.ServiceFilter != "" {
|
||||||
|
r.params.Set("service", params.ServiceFilter)
|
||||||
|
}
|
||||||
|
if params.TagFilter != "" {
|
||||||
|
r.params.Set("tag", params.TagFilter)
|
||||||
|
}
|
||||||
|
if params.Payload != nil {
|
||||||
|
r.body = bytes.NewReader(params.Payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
rtt, resp, err := requireOK(e.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
var out UserEvent
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
return out.ID, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List is used to get the most recent events an agent has received.
|
||||||
|
// This list can be optionally filtered by the name. This endpoint supports
|
||||||
|
// quasi-blocking queries. The index is not monotonic, nor does it provide provide
|
||||||
|
// LastContact or KnownLeader.
|
||||||
|
func (e *Event) List(name string, q *QueryOptions) ([]*UserEvent, *QueryMeta, error) {
|
||||||
|
r := e.c.newRequest("GET", "/v1/event/list")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
if name != "" {
|
||||||
|
r.params.Set("name", name)
|
||||||
|
}
|
||||||
|
rtt, resp, err := requireOK(e.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var entries []*UserEvent
|
||||||
|
if err := decodeBody(resp, &entries); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return entries, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDToIndex is a bit of a hack. This simulates the index generation to
|
||||||
|
// convert an event ID into a WaitIndex.
|
||||||
|
func (e *Event) IDToIndex(uuid string) uint64 {
|
||||||
|
lower := uuid[0:8] + uuid[9:13] + uuid[14:18]
|
||||||
|
upper := uuid[19:23] + uuid[24:36]
|
||||||
|
lowVal, err := strconv.ParseUint(lower, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to convert " + lower)
|
||||||
|
}
|
||||||
|
highVal, err := strconv.ParseUint(upper, 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to convert " + upper)
|
||||||
|
}
|
||||||
|
return lowVal ^ highVal
|
||||||
|
}
|
16
vendor/github.com/hashicorp/consul/api/go.mod
generated
vendored
Normal file
16
vendor/github.com/hashicorp/consul/api/go.mod
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
module github.com/hashicorp/consul/api
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
replace github.com/hashicorp/consul/sdk => ../sdk
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/hashicorp/consul/sdk v0.6.0
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
|
github.com/hashicorp/go-hclog v0.12.0
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1
|
||||||
|
github.com/hashicorp/serf v0.9.3
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2
|
||||||
|
github.com/stretchr/testify v1.4.0
|
||||||
|
)
|
131
vendor/github.com/hashicorp/consul/api/go.sum
generated
vendored
Normal file
131
vendor/github.com/hashicorp/consul/api/go.sum
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||||
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
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.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
|
||||||
|
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
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.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.3/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-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
|
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
|
||||||
|
github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g=
|
||||||
|
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||||
|
github.com/hashicorp/serf v0.9.3 h1:AVF6JDQQens6nMHT9OGERBvK0f8rPrAGILnsKLr6lzM=
|
||||||
|
github.com/hashicorp/serf v0.9.3/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||||
|
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||||
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||||
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
|
||||||
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU=
|
||||||
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
|
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/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 v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs=
|
||||||
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||||
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 h1:KYQXGkl6vs02hK7pK4eIbw0NpNPedieTSTEiJ//bwGs=
|
||||||
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
|
||||||
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||||
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5 h1:x6r4Jo0KNzOOzYd8lbcRsqjuqEASK6ob3auvWYM4/8U=
|
||||||
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
|
||||||
|
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
375
vendor/github.com/hashicorp/consul/api/health.go
generated
vendored
Normal file
375
vendor/github.com/hashicorp/consul/api/health.go
generated
vendored
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HealthAny is special, and is used as a wild card,
|
||||||
|
// not as a specific state.
|
||||||
|
HealthAny = "any"
|
||||||
|
HealthPassing = "passing"
|
||||||
|
HealthWarning = "warning"
|
||||||
|
HealthCritical = "critical"
|
||||||
|
HealthMaint = "maintenance"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
serviceHealth = "service"
|
||||||
|
connectHealth = "connect"
|
||||||
|
ingressHealth = "ingress"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NodeMaint is the special key set by a node in maintenance mode.
|
||||||
|
NodeMaint = "_node_maintenance"
|
||||||
|
|
||||||
|
// ServiceMaintPrefix is the prefix for a service in maintenance mode.
|
||||||
|
ServiceMaintPrefix = "_service_maintenance:"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HealthCheck is used to represent a single check
|
||||||
|
type HealthCheck struct {
|
||||||
|
Node string
|
||||||
|
CheckID string
|
||||||
|
Name string
|
||||||
|
Status string
|
||||||
|
Notes string
|
||||||
|
Output string
|
||||||
|
ServiceID string
|
||||||
|
ServiceName string
|
||||||
|
ServiceTags []string
|
||||||
|
Type string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
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
|
||||||
|
Body 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 (t *HealthCheckDefinition) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
type Alias HealthCheckDefinition
|
||||||
|
aux := &struct {
|
||||||
|
IntervalDuration interface{}
|
||||||
|
TimeoutDuration interface{}
|
||||||
|
DeregisterCriticalServiceAfterDuration interface{}
|
||||||
|
*Alias
|
||||||
|
}{
|
||||||
|
Alias: (*Alias)(t),
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(data, &aux); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the values into both the time.Duration and old ReadableDuration fields.
|
||||||
|
|
||||||
|
if aux.IntervalDuration == nil {
|
||||||
|
t.IntervalDuration = time.Duration(t.Interval)
|
||||||
|
} else {
|
||||||
|
switch v := aux.IntervalDuration.(type) {
|
||||||
|
case string:
|
||||||
|
if t.IntervalDuration, err = time.ParseDuration(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
t.IntervalDuration = time.Duration(v)
|
||||||
|
}
|
||||||
|
t.Interval = ReadableDuration(t.IntervalDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
if aux.TimeoutDuration == nil {
|
||||||
|
t.TimeoutDuration = time.Duration(t.Timeout)
|
||||||
|
} else {
|
||||||
|
switch v := aux.TimeoutDuration.(type) {
|
||||||
|
case string:
|
||||||
|
if t.TimeoutDuration, err = time.ParseDuration(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
t.TimeoutDuration = time.Duration(v)
|
||||||
|
}
|
||||||
|
t.Timeout = ReadableDuration(t.TimeoutDuration)
|
||||||
|
}
|
||||||
|
if aux.DeregisterCriticalServiceAfterDuration == nil {
|
||||||
|
t.DeregisterCriticalServiceAfterDuration = time.Duration(t.DeregisterCriticalServiceAfter)
|
||||||
|
} else {
|
||||||
|
switch v := aux.DeregisterCriticalServiceAfterDuration.(type) {
|
||||||
|
case string:
|
||||||
|
if t.DeregisterCriticalServiceAfterDuration, err = time.ParseDuration(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
t.DeregisterCriticalServiceAfterDuration = time.Duration(v)
|
||||||
|
}
|
||||||
|
t.DeregisterCriticalServiceAfter = ReadableDuration(t.DeregisterCriticalServiceAfterDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthChecks is a collection of HealthCheck structs.
|
||||||
|
type HealthChecks []*HealthCheck
|
||||||
|
|
||||||
|
// AggregatedStatus returns the "best" status for the list of health checks.
|
||||||
|
// Because a given entry may have many service and node-level health checks
|
||||||
|
// attached, this function determines the best representative of the status as
|
||||||
|
// as single string using the following heuristic:
|
||||||
|
//
|
||||||
|
// maintenance > critical > warning > passing
|
||||||
|
//
|
||||||
|
func (c HealthChecks) AggregatedStatus() string {
|
||||||
|
var passing, warning, critical, maintenance bool
|
||||||
|
for _, check := range c {
|
||||||
|
id := check.CheckID
|
||||||
|
if id == NodeMaint || strings.HasPrefix(id, ServiceMaintPrefix) {
|
||||||
|
maintenance = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch check.Status {
|
||||||
|
case HealthPassing:
|
||||||
|
passing = true
|
||||||
|
case HealthWarning:
|
||||||
|
warning = true
|
||||||
|
case HealthCritical:
|
||||||
|
critical = true
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case maintenance:
|
||||||
|
return HealthMaint
|
||||||
|
case critical:
|
||||||
|
return HealthCritical
|
||||||
|
case warning:
|
||||||
|
return HealthWarning
|
||||||
|
case passing:
|
||||||
|
return HealthPassing
|
||||||
|
default:
|
||||||
|
return HealthPassing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceEntry is used for the health service endpoint
|
||||||
|
type ServiceEntry struct {
|
||||||
|
Node *Node
|
||||||
|
Service *AgentService
|
||||||
|
Checks HealthChecks
|
||||||
|
}
|
||||||
|
|
||||||
|
// Health can be used to query the Health endpoints
|
||||||
|
type Health struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Health returns a handle to the health endpoints
|
||||||
|
func (c *Client) Health() *Health {
|
||||||
|
return &Health{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node is used to query for checks belonging to a given node
|
||||||
|
func (h *Health) Node(node string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
|
||||||
|
r := h.c.newRequest("GET", "/v1/health/node/"+node)
|
||||||
|
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 HealthChecks
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks is used to return the checks associated with a service
|
||||||
|
func (h *Health) Checks(service string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
|
||||||
|
r := h.c.newRequest("GET", "/v1/health/checks/"+service)
|
||||||
|
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 HealthChecks
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service is used to query health information along with service info
|
||||||
|
// 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) {
|
||||||
|
var tags []string
|
||||||
|
if tag != "" {
|
||||||
|
tags = []string{tag}
|
||||||
|
}
|
||||||
|
return h.service(service, tags, passingOnly, q, serviceHealth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Health) ServiceMultipleTags(service string, tags []string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||||
|
return h.service(service, tags, passingOnly, q, serviceHealth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, connectHealth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Health) ConnectMultipleTags(service string, tags []string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||||
|
return h.service(service, tags, passingOnly, q, connectHealth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ingress is equivalent to Connect except that it will only return associated
|
||||||
|
// ingress gateways for the requested service.
|
||||||
|
func (h *Health) Ingress(service string, passingOnly bool, q *QueryOptions) ([]*ServiceEntry, *QueryMeta, error) {
|
||||||
|
var tags []string
|
||||||
|
return h.service(service, tags, passingOnly, q, ingressHealth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Health) service(service string, tags []string, passingOnly bool, q *QueryOptions, healthType string) ([]*ServiceEntry, *QueryMeta, error) {
|
||||||
|
var path string
|
||||||
|
switch healthType {
|
||||||
|
case connectHealth:
|
||||||
|
path = "/v1/health/connect/" + service
|
||||||
|
case ingressHealth:
|
||||||
|
path = "/v1/health/ingress/" + service
|
||||||
|
default:
|
||||||
|
path = "/v1/health/service/" + 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")
|
||||||
|
}
|
||||||
|
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 []*ServiceEntry
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// State is used to retrieve all the checks in a given state.
|
||||||
|
// The wildcard "any" state can also be used for all checks.
|
||||||
|
func (h *Health) State(state string, q *QueryOptions) (HealthChecks, *QueryMeta, error) {
|
||||||
|
switch state {
|
||||||
|
case HealthAny:
|
||||||
|
case HealthWarning:
|
||||||
|
case HealthCritical:
|
||||||
|
case HealthPassing:
|
||||||
|
default:
|
||||||
|
return nil, nil, fmt.Errorf("Unsupported state: %v", state)
|
||||||
|
}
|
||||||
|
r := h.c.newRequest("GET", "/v1/health/state/"+state)
|
||||||
|
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 HealthChecks
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
290
vendor/github.com/hashicorp/consul/api/kv.go
generated
vendored
Normal file
290
vendor/github.com/hashicorp/consul/api/kv.go
generated
vendored
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KVPair is used to represent a single K/V entry
|
||||||
|
type KVPair struct {
|
||||||
|
// Key is the name of the key. It is also part of the URL path when accessed
|
||||||
|
// via the API.
|
||||||
|
Key string
|
||||||
|
|
||||||
|
// CreateIndex holds the index corresponding the creation of this KVPair. This
|
||||||
|
// is a read-only field.
|
||||||
|
CreateIndex uint64
|
||||||
|
|
||||||
|
// ModifyIndex is used for the Check-And-Set operations and can also be fed
|
||||||
|
// back into the WaitIndex of the QueryOptions in order to perform blocking
|
||||||
|
// queries.
|
||||||
|
ModifyIndex uint64
|
||||||
|
|
||||||
|
// LockIndex holds the index corresponding to a lock on this key, if any. This
|
||||||
|
// is a read-only field.
|
||||||
|
LockIndex uint64
|
||||||
|
|
||||||
|
// Flags are any user-defined flags on the key. It is up to the implementer
|
||||||
|
// to check these values, since Consul does not treat them specially.
|
||||||
|
Flags uint64
|
||||||
|
|
||||||
|
// Value is the value for the key. This can be any value, but it will be
|
||||||
|
// base64 encoded upon transport.
|
||||||
|
Value []byte
|
||||||
|
|
||||||
|
// Session is a string representing the ID of the session. Any other
|
||||||
|
// interactions with this key over the same session must specify the same
|
||||||
|
// session ID.
|
||||||
|
Session string
|
||||||
|
|
||||||
|
// Namespace is the namespace the KVPair is associated with
|
||||||
|
// Namespacing is a Consul Enterprise feature.
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KVPairs is a list of KVPair objects
|
||||||
|
type KVPairs []*KVPair
|
||||||
|
|
||||||
|
// KV is used to manipulate the K/V API
|
||||||
|
type KV struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// KV is used to return a handle to the K/V apis
|
||||||
|
func (c *Client) KV() *KV {
|
||||||
|
return &KV{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is used to lookup a single key. The returned pointer
|
||||||
|
// to the KVPair will be nil if the key does not exist.
|
||||||
|
func (k *KV) Get(key string, q *QueryOptions) (*KVPair, *QueryMeta, error) {
|
||||||
|
resp, qm, err := k.getInternal(key, nil, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
return nil, qm, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var entries []*KVPair
|
||||||
|
if err := decodeBody(resp, &entries); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if len(entries) > 0 {
|
||||||
|
return entries[0], qm, nil
|
||||||
|
}
|
||||||
|
return nil, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List is used to lookup all keys under a prefix
|
||||||
|
func (k *KV) List(prefix string, q *QueryOptions) (KVPairs, *QueryMeta, error) {
|
||||||
|
resp, qm, err := k.getInternal(prefix, map[string]string{"recurse": ""}, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
return nil, qm, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var entries []*KVPair
|
||||||
|
if err := decodeBody(resp, &entries); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return entries, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys is used to list all the keys under a prefix. Optionally,
|
||||||
|
// a separator can be used to limit the responses.
|
||||||
|
func (k *KV) Keys(prefix, separator string, q *QueryOptions) ([]string, *QueryMeta, error) {
|
||||||
|
params := map[string]string{"keys": ""}
|
||||||
|
if separator != "" {
|
||||||
|
params["separator"] = separator
|
||||||
|
}
|
||||||
|
resp, qm, err := k.getInternal(prefix, params, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
return nil, qm, nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var entries []string
|
||||||
|
if err := decodeBody(resp, &entries); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return entries, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KV) getInternal(key string, params map[string]string, q *QueryOptions) (*http.Response, *QueryMeta, error) {
|
||||||
|
r := k.c.newRequest("GET", "/v1/kv/"+strings.TrimPrefix(key, "/"))
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
for param, val := range params {
|
||||||
|
r.params.Set(param, val)
|
||||||
|
}
|
||||||
|
rtt, resp, err := k.c.doRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil, qm, nil
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil, nil, fmt.Errorf("Unexpected response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return resp, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put is used to write a new value. Only the
|
||||||
|
// Key, Flags and Value is respected.
|
||||||
|
func (k *KV) Put(p *KVPair, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
params := make(map[string]string, 1)
|
||||||
|
if p.Flags != 0 {
|
||||||
|
params["flags"] = strconv.FormatUint(p.Flags, 10)
|
||||||
|
}
|
||||||
|
_, wm, err := k.put(p.Key, params, p.Value, q)
|
||||||
|
return wm, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAS is used for a Check-And-Set operation. The Key,
|
||||||
|
// ModifyIndex, Flags and Value are respected. Returns true
|
||||||
|
// on success or false on failures.
|
||||||
|
func (k *KV) CAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
params := make(map[string]string, 2)
|
||||||
|
if p.Flags != 0 {
|
||||||
|
params["flags"] = strconv.FormatUint(p.Flags, 10)
|
||||||
|
}
|
||||||
|
params["cas"] = strconv.FormatUint(p.ModifyIndex, 10)
|
||||||
|
return k.put(p.Key, params, p.Value, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire is used for a lock acquisition operation. The Key,
|
||||||
|
// Flags, Value and Session are respected. Returns true
|
||||||
|
// on success or false on failures.
|
||||||
|
func (k *KV) Acquire(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
params := make(map[string]string, 2)
|
||||||
|
if p.Flags != 0 {
|
||||||
|
params["flags"] = strconv.FormatUint(p.Flags, 10)
|
||||||
|
}
|
||||||
|
params["acquire"] = p.Session
|
||||||
|
return k.put(p.Key, params, p.Value, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release is used for a lock release operation. The Key,
|
||||||
|
// Flags, Value and Session are respected. Returns true
|
||||||
|
// on success or false on failures.
|
||||||
|
func (k *KV) Release(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
params := make(map[string]string, 2)
|
||||||
|
if p.Flags != 0 {
|
||||||
|
params["flags"] = strconv.FormatUint(p.Flags, 10)
|
||||||
|
}
|
||||||
|
params["release"] = p.Session
|
||||||
|
return k.put(p.Key, params, p.Value, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KV) put(key string, params map[string]string, body []byte, q *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
if len(key) > 0 && key[0] == '/' {
|
||||||
|
return false, nil, fmt.Errorf("Invalid key. Key must not begin with a '/': %s", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := k.c.newRequest("PUT", "/v1/kv/"+key)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
for param, val := range params {
|
||||||
|
r.params.Set(param, val)
|
||||||
|
}
|
||||||
|
r.body = bytes.NewReader(body)
|
||||||
|
rtt, resp, err := requireOK(k.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &WriteMeta{}
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return false, nil, fmt.Errorf("Failed to read response: %v", err)
|
||||||
|
}
|
||||||
|
res := strings.Contains(buf.String(), "true")
|
||||||
|
return res, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete is used to delete a single key
|
||||||
|
func (k *KV) Delete(key string, w *WriteOptions) (*WriteMeta, error) {
|
||||||
|
_, qm, err := k.deleteInternal(key, nil, w)
|
||||||
|
return qm, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCAS is used for a Delete Check-And-Set operation. The Key
|
||||||
|
// and ModifyIndex are respected. Returns true on success or false on failures.
|
||||||
|
func (k *KV) DeleteCAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
params := map[string]string{
|
||||||
|
"cas": strconv.FormatUint(p.ModifyIndex, 10),
|
||||||
|
}
|
||||||
|
return k.deleteInternal(p.Key, params, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTree is used to delete all keys under a prefix
|
||||||
|
func (k *KV) DeleteTree(prefix string, w *WriteOptions) (*WriteMeta, error) {
|
||||||
|
_, qm, err := k.deleteInternal(prefix, map[string]string{"recurse": ""}, w)
|
||||||
|
return qm, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *KV) deleteInternal(key string, params map[string]string, q *WriteOptions) (bool, *WriteMeta, error) {
|
||||||
|
r := k.c.newRequest("DELETE", "/v1/kv/"+strings.TrimPrefix(key, "/"))
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
for param, val := range params {
|
||||||
|
r.params.Set(param, val)
|
||||||
|
}
|
||||||
|
rtt, resp, err := requireOK(k.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &WriteMeta{}
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return false, nil, fmt.Errorf("Failed to read response: %v", err)
|
||||||
|
}
|
||||||
|
res := strings.Contains(buf.String(), "true")
|
||||||
|
return res, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
var ops TxnOps
|
||||||
|
for _, op := range txn {
|
||||||
|
ops = append(ops, &TxnOp{KV: op})
|
||||||
|
}
|
||||||
|
|
||||||
|
respOk, txnResp, qm, err := k.c.txn(ops, q)
|
||||||
|
if 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 respOk, &kvResp, qm, nil
|
||||||
|
}
|
406
vendor/github.com/hashicorp/consul/api/lock.go
generated
vendored
Normal file
406
vendor/github.com/hashicorp/consul/api/lock.go
generated
vendored
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultLockSessionName is the Session Name we assign if none is provided
|
||||||
|
DefaultLockSessionName = "Consul API Lock"
|
||||||
|
|
||||||
|
// DefaultLockSessionTTL is the default session TTL if no Session is provided
|
||||||
|
// when creating a new Lock. This is used because we do not have another
|
||||||
|
// other check to depend upon.
|
||||||
|
DefaultLockSessionTTL = "15s"
|
||||||
|
|
||||||
|
// DefaultLockWaitTime is how long we block for at a time to check if lock
|
||||||
|
// acquisition is possible. This affects the minimum time it takes to cancel
|
||||||
|
// a Lock acquisition.
|
||||||
|
DefaultLockWaitTime = 15 * time.Second
|
||||||
|
|
||||||
|
// DefaultLockRetryTime is how long we wait after a failed lock acquisition
|
||||||
|
// before attempting to do the lock again. This is so that once a lock-delay
|
||||||
|
// is in effect, we do not hot loop retrying the acquisition.
|
||||||
|
DefaultLockRetryTime = 5 * time.Second
|
||||||
|
|
||||||
|
// DefaultMonitorRetryTime is how long we wait after a failed monitor check
|
||||||
|
// of a lock (500 response code). This allows the monitor to ride out brief
|
||||||
|
// periods of unavailability, subject to the MonitorRetries setting in the
|
||||||
|
// lock options which is by default set to 0, disabling this feature. This
|
||||||
|
// affects locks and semaphores.
|
||||||
|
DefaultMonitorRetryTime = 2 * time.Second
|
||||||
|
|
||||||
|
// LockFlagValue is a magic flag we set to indicate a key
|
||||||
|
// is being used for a lock. It is used to detect a potential
|
||||||
|
// conflict with a semaphore.
|
||||||
|
LockFlagValue = 0x2ddccbc058a50c18
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrLockHeld is returned if we attempt to double lock
|
||||||
|
ErrLockHeld = fmt.Errorf("Lock already held")
|
||||||
|
|
||||||
|
// ErrLockNotHeld is returned if we attempt to unlock a lock
|
||||||
|
// that we do not hold.
|
||||||
|
ErrLockNotHeld = fmt.Errorf("Lock not held")
|
||||||
|
|
||||||
|
// ErrLockInUse is returned if we attempt to destroy a lock
|
||||||
|
// that is in use.
|
||||||
|
ErrLockInUse = fmt.Errorf("Lock in use")
|
||||||
|
|
||||||
|
// ErrLockConflict is returned if the flags on a key
|
||||||
|
// used for a lock do not match expectation
|
||||||
|
ErrLockConflict = fmt.Errorf("Existing key does not match lock use")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lock is used to implement client-side leader election. It is follows the
|
||||||
|
// algorithm as described here: https://www.consul.io/docs/guides/leader-election.html.
|
||||||
|
type Lock struct {
|
||||||
|
c *Client
|
||||||
|
opts *LockOptions
|
||||||
|
|
||||||
|
isHeld bool
|
||||||
|
sessionRenew chan struct{}
|
||||||
|
lockSession string
|
||||||
|
l sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// LockOptions is used to parameterize the Lock behavior.
|
||||||
|
type LockOptions struct {
|
||||||
|
Key string // Must be set and have write permissions
|
||||||
|
Value []byte // Optional, value to associate with the lock
|
||||||
|
Session string // Optional, created if not specified
|
||||||
|
SessionOpts *SessionEntry // Optional, options to use when creating a session
|
||||||
|
SessionName string // Optional, defaults to DefaultLockSessionName (ignored if SessionOpts is given)
|
||||||
|
SessionTTL string // Optional, defaults to DefaultLockSessionTTL (ignored if SessionOpts is given)
|
||||||
|
MonitorRetries int // Optional, defaults to 0 which means no retries
|
||||||
|
MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime
|
||||||
|
LockWaitTime time.Duration // Optional, defaults to DefaultLockWaitTime
|
||||||
|
LockTryOnce bool // Optional, defaults to false which means try forever
|
||||||
|
Namespace string `json:",omitempty"` // Optional, defaults to API client config, namespace of ACL token, or "default" namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// LockKey returns a handle to a lock struct which can be used
|
||||||
|
// to acquire and release the mutex. The key used must have
|
||||||
|
// write permissions.
|
||||||
|
func (c *Client) LockKey(key string) (*Lock, error) {
|
||||||
|
opts := &LockOptions{
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
return c.LockOpts(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LockOpts returns a handle to a lock struct which can be used
|
||||||
|
// to acquire and release the mutex. The key used must have
|
||||||
|
// write permissions.
|
||||||
|
func (c *Client) LockOpts(opts *LockOptions) (*Lock, error) {
|
||||||
|
if opts.Key == "" {
|
||||||
|
return nil, fmt.Errorf("missing key")
|
||||||
|
}
|
||||||
|
if opts.SessionName == "" {
|
||||||
|
opts.SessionName = DefaultLockSessionName
|
||||||
|
}
|
||||||
|
if opts.SessionTTL == "" {
|
||||||
|
opts.SessionTTL = DefaultLockSessionTTL
|
||||||
|
} else {
|
||||||
|
if _, err := time.ParseDuration(opts.SessionTTL); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid SessionTTL: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if opts.MonitorRetryTime == 0 {
|
||||||
|
opts.MonitorRetryTime = DefaultMonitorRetryTime
|
||||||
|
}
|
||||||
|
if opts.LockWaitTime == 0 {
|
||||||
|
opts.LockWaitTime = DefaultLockWaitTime
|
||||||
|
}
|
||||||
|
l := &Lock{
|
||||||
|
c: c,
|
||||||
|
opts: opts,
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock attempts to acquire the lock and blocks while doing so.
|
||||||
|
// Providing a non-nil stopCh can be used to abort the lock attempt.
|
||||||
|
// Returns a channel that is closed if our lock is lost or an error.
|
||||||
|
// This channel could be closed at any time due to session invalidation,
|
||||||
|
// communication errors, operator intervention, etc. It is NOT safe to
|
||||||
|
// assume that the lock is held until Unlock() unless the Session is specifically
|
||||||
|
// created without any associated health checks. By default Consul sessions
|
||||||
|
// prefer liveness over safety and an application must be able to handle
|
||||||
|
// the lock being lost.
|
||||||
|
func (l *Lock) Lock(stopCh <-chan struct{}) (<-chan struct{}, error) {
|
||||||
|
// Hold the lock as we try to acquire
|
||||||
|
l.l.Lock()
|
||||||
|
defer l.l.Unlock()
|
||||||
|
|
||||||
|
// Check if we already hold the lock
|
||||||
|
if l.isHeld {
|
||||||
|
return nil, ErrLockHeld
|
||||||
|
}
|
||||||
|
|
||||||
|
wOpts := WriteOptions{
|
||||||
|
Namespace: l.opts.Namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to create a session first
|
||||||
|
l.lockSession = l.opts.Session
|
||||||
|
if l.lockSession == "" {
|
||||||
|
s, err := l.createSession()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create session: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l.sessionRenew = make(chan struct{})
|
||||||
|
l.lockSession = s
|
||||||
|
|
||||||
|
session := l.c.Session()
|
||||||
|
go session.RenewPeriodic(l.opts.SessionTTL, s, &wOpts, l.sessionRenew)
|
||||||
|
|
||||||
|
// If we fail to acquire the lock, cleanup the session
|
||||||
|
defer func() {
|
||||||
|
if !l.isHeld {
|
||||||
|
close(l.sessionRenew)
|
||||||
|
l.sessionRenew = nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the query options
|
||||||
|
kv := l.c.KV()
|
||||||
|
qOpts := QueryOptions{
|
||||||
|
WaitTime: l.opts.LockWaitTime,
|
||||||
|
Namespace: l.opts.Namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
attempts := 0
|
||||||
|
WAIT:
|
||||||
|
// Check if we should quit
|
||||||
|
select {
|
||||||
|
case <-stopCh:
|
||||||
|
return nil, nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the one-shot mode.
|
||||||
|
if l.opts.LockTryOnce && attempts > 0 {
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
if elapsed > l.opts.LockWaitTime {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query wait time should not exceed the lock wait time
|
||||||
|
qOpts.WaitTime = l.opts.LockWaitTime - elapsed
|
||||||
|
}
|
||||||
|
attempts++
|
||||||
|
|
||||||
|
// Look for an existing lock, blocking until not taken
|
||||||
|
pair, meta, err := kv.Get(l.opts.Key, &qOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read lock: %v", err)
|
||||||
|
}
|
||||||
|
if pair != nil && pair.Flags != LockFlagValue {
|
||||||
|
return nil, ErrLockConflict
|
||||||
|
}
|
||||||
|
locked := false
|
||||||
|
if pair != nil && pair.Session == l.lockSession {
|
||||||
|
goto HELD
|
||||||
|
}
|
||||||
|
if pair != nil && pair.Session != "" {
|
||||||
|
qOpts.WaitIndex = meta.LastIndex
|
||||||
|
goto WAIT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to acquire the lock
|
||||||
|
pair = l.lockEntry(l.lockSession)
|
||||||
|
|
||||||
|
locked, _, err = kv.Acquire(pair, &wOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to acquire lock: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the case of not getting the lock
|
||||||
|
if !locked {
|
||||||
|
// Determine why the lock failed
|
||||||
|
qOpts.WaitIndex = 0
|
||||||
|
pair, meta, err = kv.Get(l.opts.Key, &qOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pair != nil && pair.Session != "" {
|
||||||
|
//If the session is not null, this means that a wait can safely happen
|
||||||
|
//using a long poll
|
||||||
|
qOpts.WaitIndex = meta.LastIndex
|
||||||
|
goto WAIT
|
||||||
|
} else {
|
||||||
|
// If the session is empty and the lock failed to acquire, then it means
|
||||||
|
// a lock-delay is in effect and a timed wait must be used
|
||||||
|
select {
|
||||||
|
case <-time.After(DefaultLockRetryTime):
|
||||||
|
goto WAIT
|
||||||
|
case <-stopCh:
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HELD:
|
||||||
|
// Watch to ensure we maintain leadership
|
||||||
|
leaderCh := make(chan struct{})
|
||||||
|
go l.monitorLock(l.lockSession, leaderCh)
|
||||||
|
|
||||||
|
// Set that we own the lock
|
||||||
|
l.isHeld = true
|
||||||
|
|
||||||
|
// Locked! All done
|
||||||
|
return leaderCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock released the lock. It is an error to call this
|
||||||
|
// if the lock is not currently held.
|
||||||
|
func (l *Lock) Unlock() error {
|
||||||
|
// Hold the lock as we try to release
|
||||||
|
l.l.Lock()
|
||||||
|
defer l.l.Unlock()
|
||||||
|
|
||||||
|
// Ensure the lock is actually held
|
||||||
|
if !l.isHeld {
|
||||||
|
return ErrLockNotHeld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set that we no longer own the lock
|
||||||
|
l.isHeld = false
|
||||||
|
|
||||||
|
// Stop the session renew
|
||||||
|
if l.sessionRenew != nil {
|
||||||
|
defer func() {
|
||||||
|
close(l.sessionRenew)
|
||||||
|
l.sessionRenew = nil
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the lock entry, and clear the lock session
|
||||||
|
lockEnt := l.lockEntry(l.lockSession)
|
||||||
|
l.lockSession = ""
|
||||||
|
|
||||||
|
// Release the lock explicitly
|
||||||
|
kv := l.c.KV()
|
||||||
|
w := WriteOptions{Namespace: l.opts.Namespace}
|
||||||
|
|
||||||
|
_, _, err := kv.Release(lockEnt, &w)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to release lock: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy is used to cleanup the lock entry. It is not necessary
|
||||||
|
// to invoke. It will fail if the lock is in use.
|
||||||
|
func (l *Lock) Destroy() error {
|
||||||
|
// Hold the lock as we try to release
|
||||||
|
l.l.Lock()
|
||||||
|
defer l.l.Unlock()
|
||||||
|
|
||||||
|
// Check if we already hold the lock
|
||||||
|
if l.isHeld {
|
||||||
|
return ErrLockHeld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for an existing lock
|
||||||
|
kv := l.c.KV()
|
||||||
|
q := QueryOptions{Namespace: l.opts.Namespace}
|
||||||
|
|
||||||
|
pair, _, err := kv.Get(l.opts.Key, &q)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read lock: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to do if the lock does not exist
|
||||||
|
if pair == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for possible flag conflict
|
||||||
|
if pair.Flags != LockFlagValue {
|
||||||
|
return ErrLockConflict
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it is in use
|
||||||
|
if pair.Session != "" {
|
||||||
|
return ErrLockInUse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt the delete
|
||||||
|
w := WriteOptions{Namespace: l.opts.Namespace}
|
||||||
|
didRemove, _, err := kv.DeleteCAS(pair, &w)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to remove lock: %v", err)
|
||||||
|
}
|
||||||
|
if !didRemove {
|
||||||
|
return ErrLockInUse
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createSession is used to create a new managed session
|
||||||
|
func (l *Lock) createSession() (string, error) {
|
||||||
|
session := l.c.Session()
|
||||||
|
se := l.opts.SessionOpts
|
||||||
|
if se == nil {
|
||||||
|
se = &SessionEntry{
|
||||||
|
Name: l.opts.SessionName,
|
||||||
|
TTL: l.opts.SessionTTL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w := WriteOptions{Namespace: l.opts.Namespace}
|
||||||
|
id, _, err := session.Create(se, &w)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// lockEntry returns a formatted KVPair for the lock
|
||||||
|
func (l *Lock) lockEntry(session string) *KVPair {
|
||||||
|
return &KVPair{
|
||||||
|
Key: l.opts.Key,
|
||||||
|
Value: l.opts.Value,
|
||||||
|
Session: session,
|
||||||
|
Flags: LockFlagValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// monitorLock is a long running routine to monitor a lock ownership
|
||||||
|
// It closes the stopCh if we lose our leadership.
|
||||||
|
func (l *Lock) monitorLock(session string, stopCh chan struct{}) {
|
||||||
|
defer close(stopCh)
|
||||||
|
kv := l.c.KV()
|
||||||
|
opts := QueryOptions{
|
||||||
|
RequireConsistent: true,
|
||||||
|
Namespace: l.opts.Namespace,
|
||||||
|
}
|
||||||
|
WAIT:
|
||||||
|
retries := l.opts.MonitorRetries
|
||||||
|
RETRY:
|
||||||
|
pair, meta, err := kv.Get(l.opts.Key, &opts)
|
||||||
|
if err != nil {
|
||||||
|
// If configured we can try to ride out a brief Consul unavailability
|
||||||
|
// by doing retries. Note that we have to attempt the retry in a non-
|
||||||
|
// blocking fashion so that we have a clean place to reset the retry
|
||||||
|
// counter if service is restored.
|
||||||
|
if retries > 0 && IsRetryableError(err) {
|
||||||
|
time.Sleep(l.opts.MonitorRetryTime)
|
||||||
|
retries--
|
||||||
|
opts.WaitIndex = 0
|
||||||
|
goto RETRY
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pair != nil && pair.Session == session {
|
||||||
|
opts.WaitIndex = meta.LastIndex
|
||||||
|
goto WAIT
|
||||||
|
}
|
||||||
|
}
|
159
vendor/github.com/hashicorp/consul/api/namespace.go
generated
vendored
Normal file
159
vendor/github.com/hashicorp/consul/api/namespace.go
generated
vendored
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Namespace is the configuration of a single namespace. Namespacing is a Consul Enterprise feature.
|
||||||
|
type Namespace struct {
|
||||||
|
// Name is the name of the Namespace. It must be unique and
|
||||||
|
// must be a DNS hostname. There are also other reserved names
|
||||||
|
// that may not be used.
|
||||||
|
Name string `json:"Name"`
|
||||||
|
|
||||||
|
// Description is where the user puts any information they want
|
||||||
|
// about the namespace. It is not used internally.
|
||||||
|
Description string `json:"Description,omitempty"`
|
||||||
|
|
||||||
|
// ACLs is the configuration of ACLs for this namespace. It has its
|
||||||
|
// own struct so that we can add more to it in the future.
|
||||||
|
// This is nullable so that we can omit if empty when encoding in JSON
|
||||||
|
ACLs *NamespaceACLConfig `json:"ACLs,omitempty"`
|
||||||
|
|
||||||
|
// Meta is a map that can be used to add kv metadata to the namespace definition
|
||||||
|
Meta map[string]string `json:"Meta,omitempty"`
|
||||||
|
|
||||||
|
// DeletedAt is the time when the Namespace was marked for deletion
|
||||||
|
// This is nullable so that we can omit if empty when encoding in JSON
|
||||||
|
DeletedAt *time.Time `json:"DeletedAt,omitempty"`
|
||||||
|
|
||||||
|
// CreateIndex is the Raft index at which the Namespace was created
|
||||||
|
CreateIndex uint64 `json:"CreateIndex,omitempty"`
|
||||||
|
|
||||||
|
// ModifyIndex is the latest Raft index at which the Namespace was modified.
|
||||||
|
ModifyIndex uint64 `json:"ModifyIndex,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceACLConfig is the Namespace specific ACL configuration container
|
||||||
|
type NamespaceACLConfig struct {
|
||||||
|
// PolicyDefaults is the list of policies that should be used for the parent authorizer
|
||||||
|
// of all tokens in the associated namespace.
|
||||||
|
PolicyDefaults []ACLLink `json:"PolicyDefaults"`
|
||||||
|
// RoleDefaults is the list of roles that should be used for the parent authorizer
|
||||||
|
// of all tokens in the associated namespace.
|
||||||
|
RoleDefaults []ACLLink `json:"RoleDefaults"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespaces can be used to manage Namespaces in Consul Enterprise..
|
||||||
|
type Namespaces struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operator returns a handle to the operator endpoints.
|
||||||
|
func (c *Client) Namespaces() *Namespaces {
|
||||||
|
return &Namespaces{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Namespaces) Create(ns *Namespace, q *WriteOptions) (*Namespace, *WriteMeta, error) {
|
||||||
|
if ns.Name == "" {
|
||||||
|
return nil, nil, fmt.Errorf("Must specify a Name for Namespace creation")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := n.c.newRequest("PUT", "/v1/namespace")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = ns
|
||||||
|
rtt, resp, err := requireOK(n.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
var out Namespace
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Namespaces) Update(ns *Namespace, q *WriteOptions) (*Namespace, *WriteMeta, error) {
|
||||||
|
if ns.Name == "" {
|
||||||
|
return nil, nil, fmt.Errorf("Must specify a Name for Namespace updating")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := n.c.newRequest("PUT", "/v1/namespace/"+ns.Name)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = ns
|
||||||
|
rtt, resp, err := requireOK(n.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
var out Namespace
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Namespaces) Read(name string, q *QueryOptions) (*Namespace, *QueryMeta, error) {
|
||||||
|
var out Namespace
|
||||||
|
r := n.c.newRequest("GET", "/v1/namespace/"+name)
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
found, rtt, resp, err := requireNotFoundOrOK(n.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return &out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Namespaces) Delete(name string, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
r := n.c.newRequest("DELETE", "/v1/namespace/"+name)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
rtt, resp, err := requireOK(n.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
return wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Namespaces) List(q *QueryOptions) ([]*Namespace, *QueryMeta, error) {
|
||||||
|
var out []*Namespace
|
||||||
|
r := n.c.newRequest("GET", "/v1/namespaces")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
rtt, resp, err := requireOK(n.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
11
vendor/github.com/hashicorp/consul/api/operator.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/consul/api/operator.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Operator can be used to perform low-level operator tasks for Consul.
|
||||||
|
type Operator struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operator returns a handle to the operator endpoints.
|
||||||
|
func (c *Client) Operator() *Operator {
|
||||||
|
return &Operator{c}
|
||||||
|
}
|
194
vendor/github.com/hashicorp/consul/api/operator_area.go
generated
vendored
Normal file
194
vendor/github.com/hashicorp/consul/api/operator_area.go
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Area defines a network area.
|
||||||
|
type Area struct {
|
||||||
|
// ID is this identifier for an area (a UUID). This must be left empty
|
||||||
|
// when creating a new area.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// PeerDatacenter is the peer Consul datacenter that will make up the
|
||||||
|
// other side of this network area. Network areas always involve a pair
|
||||||
|
// of datacenters: the datacenter where the area was created, and the
|
||||||
|
// peer datacenter. This is required.
|
||||||
|
PeerDatacenter string
|
||||||
|
|
||||||
|
// RetryJoin specifies the address of Consul servers to join to, such as
|
||||||
|
// an IPs or hostnames with an optional port number. This is optional.
|
||||||
|
RetryJoin []string
|
||||||
|
|
||||||
|
// UseTLS specifies whether gossip over this area should be encrypted with TLS
|
||||||
|
// if possible.
|
||||||
|
UseTLS bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaJoinResponse is returned when a join occurs and gives the result for each
|
||||||
|
// address.
|
||||||
|
type AreaJoinResponse struct {
|
||||||
|
// The address that was joined.
|
||||||
|
Address string
|
||||||
|
|
||||||
|
// Whether or not the join was a success.
|
||||||
|
Joined bool
|
||||||
|
|
||||||
|
// If we couldn't join, this is the message with information.
|
||||||
|
Error string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerfMember is a generic structure for reporting information about members in
|
||||||
|
// a Serf cluster. This is only used by the area endpoints right now, but this
|
||||||
|
// could be expanded to other endpoints in the future.
|
||||||
|
type SerfMember struct {
|
||||||
|
// ID is the node identifier (a UUID).
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// Name is the node name.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Addr has the IP address.
|
||||||
|
Addr net.IP
|
||||||
|
|
||||||
|
// Port is the RPC port.
|
||||||
|
Port uint16
|
||||||
|
|
||||||
|
// Datacenter is the DC name.
|
||||||
|
Datacenter string
|
||||||
|
|
||||||
|
// Role is "client", "server", or "unknown".
|
||||||
|
Role string
|
||||||
|
|
||||||
|
// Build has the version of the Consul agent.
|
||||||
|
Build string
|
||||||
|
|
||||||
|
// Protocol is the protocol of the Consul agent.
|
||||||
|
Protocol int
|
||||||
|
|
||||||
|
// Status is the Serf health status "none", "alive", "leaving", "left",
|
||||||
|
// or "failed".
|
||||||
|
Status string
|
||||||
|
|
||||||
|
// RTT is the estimated round trip time from the server handling the
|
||||||
|
// request to the this member. This will be negative if no RTT estimate
|
||||||
|
// is available.
|
||||||
|
RTT time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaCreate will create a new network area. The ID in the given structure must
|
||||||
|
// be empty and a generated ID will be returned on success.
|
||||||
|
func (op *Operator) AreaCreate(area *Area, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
r := op.c.newRequest("POST", "/v1/operator/area")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = area
|
||||||
|
rtt, resp, err := requireOK(op.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaUpdate will update the configuration of the network area with the given ID.
|
||||||
|
func (op *Operator) AreaUpdate(areaID string, area *Area, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = area
|
||||||
|
rtt, resp, err := requireOK(op.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaGet returns a single network area.
|
||||||
|
func (op *Operator) AreaGet(areaID string, q *QueryOptions) ([]*Area, *QueryMeta, error) {
|
||||||
|
var out []*Area
|
||||||
|
qm, err := op.c.query("/v1/operator/area/"+areaID, &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaList returns all the available network areas.
|
||||||
|
func (op *Operator) AreaList(q *QueryOptions) ([]*Area, *QueryMeta, error) {
|
||||||
|
var out []*Area
|
||||||
|
qm, err := op.c.query("/v1/operator/area", &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaDelete deletes the given network area.
|
||||||
|
func (op *Operator) AreaDelete(areaID string, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
r := op.c.newRequest("DELETE", "/v1/operator/area/"+areaID)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
rtt, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{}
|
||||||
|
wm.RequestTime = rtt
|
||||||
|
return wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaJoin attempts to join the given set of join addresses to the given
|
||||||
|
// network area. See the Area structure for details about join addresses.
|
||||||
|
func (op *Operator) AreaJoin(areaID string, addresses []string, q *WriteOptions) ([]*AreaJoinResponse, *WriteMeta, error) {
|
||||||
|
r := op.c.newRequest("PUT", "/v1/operator/area/"+areaID+"/join")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = addresses
|
||||||
|
rtt, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{}
|
||||||
|
wm.RequestTime = rtt
|
||||||
|
|
||||||
|
var out []*AreaJoinResponse
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AreaMembers lists the Serf information about the members in the given area.
|
||||||
|
func (op *Operator) AreaMembers(areaID string, q *QueryOptions) ([]*SerfMember, *QueryMeta, error) {
|
||||||
|
var out []*SerfMember
|
||||||
|
qm, err := op.c.query("/v1/operator/area/"+areaID+"/members", &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
232
vendor/github.com/hashicorp/consul/api/operator_autopilot.go
generated
vendored
Normal file
232
vendor/github.com/hashicorp/consul/api/operator_autopilot.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AutopilotConfiguration is used for querying/setting the Autopilot configuration.
|
||||||
|
// Autopilot helps manage operator tasks related to Consul servers like removing
|
||||||
|
// failed servers from the Raft quorum.
|
||||||
|
type AutopilotConfiguration struct {
|
||||||
|
// CleanupDeadServers controls whether to remove dead servers from the Raft
|
||||||
|
// peer list when a new server joins
|
||||||
|
CleanupDeadServers bool
|
||||||
|
|
||||||
|
// LastContactThreshold is the limit on the amount of time a server can go
|
||||||
|
// without leader contact before being considered unhealthy.
|
||||||
|
LastContactThreshold *ReadableDuration
|
||||||
|
|
||||||
|
// MaxTrailingLogs is the amount of entries in the Raft Log that a server can
|
||||||
|
// be behind before being considered unhealthy.
|
||||||
|
MaxTrailingLogs uint64
|
||||||
|
|
||||||
|
// MinQuorum sets the minimum number of servers allowed in a cluster before
|
||||||
|
// autopilot can prune dead servers.
|
||||||
|
MinQuorum uint
|
||||||
|
|
||||||
|
// ServerStabilizationTime is the minimum amount of time a server must be
|
||||||
|
// in a stable, healthy state before it can be added to the cluster. Only
|
||||||
|
// applicable with Raft protocol version 3 or higher.
|
||||||
|
ServerStabilizationTime *ReadableDuration
|
||||||
|
|
||||||
|
// (Enterprise-only) RedundancyZoneTag is the node tag to use for separating
|
||||||
|
// servers into zones for redundancy. If left blank, this feature will be disabled.
|
||||||
|
RedundancyZoneTag string
|
||||||
|
|
||||||
|
// (Enterprise-only) DisableUpgradeMigration will disable Autopilot's upgrade migration
|
||||||
|
// strategy of waiting until enough newer-versioned servers have been added to the
|
||||||
|
// cluster before promoting them to voters.
|
||||||
|
DisableUpgradeMigration bool
|
||||||
|
|
||||||
|
// (Enterprise-only) UpgradeVersionTag is the node tag to use for version info when
|
||||||
|
// performing upgrade migrations. If left blank, the Consul version will be used.
|
||||||
|
UpgradeVersionTag string
|
||||||
|
|
||||||
|
// CreateIndex holds the index corresponding the creation of this configuration.
|
||||||
|
// This is a read-only field.
|
||||||
|
CreateIndex uint64
|
||||||
|
|
||||||
|
// ModifyIndex will be set to the index of the last update when retrieving the
|
||||||
|
// Autopilot configuration. Resubmitting a configuration with
|
||||||
|
// AutopilotCASConfiguration will perform a check-and-set operation which ensures
|
||||||
|
// there hasn't been a subsequent update since the configuration was retrieved.
|
||||||
|
ModifyIndex uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerHealth is the health (from the leader's point of view) of a server.
|
||||||
|
type ServerHealth struct {
|
||||||
|
// ID is the raft ID of the server.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// Name is the node name of the server.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Address is the address of the server.
|
||||||
|
Address string
|
||||||
|
|
||||||
|
// The status of the SerfHealth check for the server.
|
||||||
|
SerfStatus string
|
||||||
|
|
||||||
|
// Version is the Consul version of the server.
|
||||||
|
Version string
|
||||||
|
|
||||||
|
// Leader is whether this server is currently the leader.
|
||||||
|
Leader bool
|
||||||
|
|
||||||
|
// LastContact is the time since this node's last contact with the leader.
|
||||||
|
LastContact *ReadableDuration
|
||||||
|
|
||||||
|
// LastTerm is the highest leader term this server has a record of in its Raft log.
|
||||||
|
LastTerm uint64
|
||||||
|
|
||||||
|
// LastIndex is the last log index this server has a record of in its Raft log.
|
||||||
|
LastIndex uint64
|
||||||
|
|
||||||
|
// Healthy is whether or not the server is healthy according to the current
|
||||||
|
// Autopilot config.
|
||||||
|
Healthy bool
|
||||||
|
|
||||||
|
// Voter is whether this is a voting server.
|
||||||
|
Voter bool
|
||||||
|
|
||||||
|
// StableSince is the last time this server's Healthy value changed.
|
||||||
|
StableSince time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperatorHealthReply is a representation of the overall health of the cluster
|
||||||
|
type OperatorHealthReply struct {
|
||||||
|
// Healthy is true if all the servers in the cluster are healthy.
|
||||||
|
Healthy bool
|
||||||
|
|
||||||
|
// FailureTolerance is the number of healthy servers that could be lost without
|
||||||
|
// an outage occurring.
|
||||||
|
FailureTolerance int
|
||||||
|
|
||||||
|
// Servers holds the health of each server.
|
||||||
|
Servers []ServerHealth
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadableDuration is a duration type that is serialized to JSON in human readable format.
|
||||||
|
type ReadableDuration time.Duration
|
||||||
|
|
||||||
|
func NewReadableDuration(dur time.Duration) *ReadableDuration {
|
||||||
|
d := ReadableDuration(dur)
|
||||||
|
return &d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ReadableDuration) String() string {
|
||||||
|
return d.Duration().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ReadableDuration) Duration() time.Duration {
|
||||||
|
if d == nil {
|
||||||
|
return time.Duration(0)
|
||||||
|
}
|
||||||
|
return time.Duration(*d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ReadableDuration) MarshalJSON() ([]byte, error) {
|
||||||
|
return []byte(fmt.Sprintf(`"%s"`, d.Duration().String())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ReadableDuration) UnmarshalJSON(raw []byte) (err error) {
|
||||||
|
if d == nil {
|
||||||
|
return fmt.Errorf("cannot unmarshal to nil pointer")
|
||||||
|
}
|
||||||
|
|
||||||
|
var dur time.Duration
|
||||||
|
str := string(raw)
|
||||||
|
if len(str) >= 2 && str[0] == '"' && str[len(str)-1] == '"' {
|
||||||
|
// quoted string
|
||||||
|
dur, err = time.ParseDuration(str[1 : len(str)-1])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no quotes, not a string
|
||||||
|
v, err := strconv.ParseFloat(str, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dur = time.Duration(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
*d = ReadableDuration(dur)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutopilotGetConfiguration is used to query the current Autopilot configuration.
|
||||||
|
func (op *Operator) AutopilotGetConfiguration(q *QueryOptions) (*AutopilotConfiguration, error) {
|
||||||
|
r := op.c.newRequest("GET", "/v1/operator/autopilot/configuration")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var out AutopilotConfiguration
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutopilotSetConfiguration is used to set the current Autopilot configuration.
|
||||||
|
func (op *Operator) AutopilotSetConfiguration(conf *AutopilotConfiguration, q *WriteOptions) error {
|
||||||
|
r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = conf
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutopilotCASConfiguration is used to perform a Check-And-Set update on the
|
||||||
|
// Autopilot configuration. The ModifyIndex value will be respected. Returns
|
||||||
|
// true on success or false on failures.
|
||||||
|
func (op *Operator) AutopilotCASConfiguration(conf *AutopilotConfiguration, q *WriteOptions) (bool, error) {
|
||||||
|
r := op.c.newRequest("PUT", "/v1/operator/autopilot/configuration")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.params.Set("cas", strconv.FormatUint(conf.ModifyIndex, 10))
|
||||||
|
r.obj = conf
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&buf, resp.Body); err != nil {
|
||||||
|
return false, fmt.Errorf("Failed to read response: %v", err)
|
||||||
|
}
|
||||||
|
res := strings.Contains(buf.String(), "true")
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutopilotServerHealth
|
||||||
|
func (op *Operator) AutopilotServerHealth(q *QueryOptions) (*OperatorHealthReply, error) {
|
||||||
|
r := op.c.newRequest("GET", "/v1/operator/autopilot/health")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var out OperatorHealthReply
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
92
vendor/github.com/hashicorp/consul/api/operator_keyring.go
generated
vendored
Normal file
92
vendor/github.com/hashicorp/consul/api/operator_keyring.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// keyringRequest is used for performing Keyring operations
|
||||||
|
type keyringRequest struct {
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyringResponse is returned when listing the gossip encryption keys
|
||||||
|
type KeyringResponse struct {
|
||||||
|
// Whether this response is for a WAN ring
|
||||||
|
WAN bool
|
||||||
|
|
||||||
|
// The datacenter name this request corresponds to
|
||||||
|
Datacenter string
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// A map of the encryption primary keys to the number of nodes they're installed on
|
||||||
|
PrimaryKeys map[string]int
|
||||||
|
|
||||||
|
// The total number of nodes in this ring
|
||||||
|
NumNodes int
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyringInstall is used to install a new gossip encryption key into the cluster
|
||||||
|
func (op *Operator) KeyringInstall(key string, q *WriteOptions) error {
|
||||||
|
r := op.c.newRequest("POST", "/v1/operator/keyring")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = keyringRequest{
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyringList is used to list the gossip keys installed in the cluster
|
||||||
|
func (op *Operator) KeyringList(q *QueryOptions) ([]*KeyringResponse, error) {
|
||||||
|
r := op.c.newRequest("GET", "/v1/operator/keyring")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var out []*KeyringResponse
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyringRemove is used to remove a gossip encryption key from the cluster
|
||||||
|
func (op *Operator) KeyringRemove(key string, q *WriteOptions) error {
|
||||||
|
r := op.c.newRequest("DELETE", "/v1/operator/keyring")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = keyringRequest{
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyringUse is used to change the active gossip encryption key
|
||||||
|
func (op *Operator) KeyringUse(key string, q *WriteOptions) error {
|
||||||
|
r := op.c.newRequest("PUT", "/v1/operator/keyring")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = keyringRequest{
|
||||||
|
Key: key,
|
||||||
|
}
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
114
vendor/github.com/hashicorp/consul/api/operator_license.go
generated
vendored
Normal file
114
vendor/github.com/hashicorp/consul/api/operator_license.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type License struct {
|
||||||
|
// The unique identifier of the license
|
||||||
|
LicenseID string `json:"license_id"`
|
||||||
|
|
||||||
|
// The customer ID associated with the license
|
||||||
|
CustomerID string `json:"customer_id"`
|
||||||
|
|
||||||
|
// If set, an identifier that should be used to lock the license to a
|
||||||
|
// particular site, cluster, etc.
|
||||||
|
InstallationID string `json:"installation_id"`
|
||||||
|
|
||||||
|
// The time at which the license was issued
|
||||||
|
IssueTime time.Time `json:"issue_time"`
|
||||||
|
|
||||||
|
// The time at which the license starts being valid
|
||||||
|
StartTime time.Time `json:"start_time"`
|
||||||
|
|
||||||
|
// The time after which the license expires
|
||||||
|
ExpirationTime time.Time `json:"expiration_time"`
|
||||||
|
|
||||||
|
// The time at which the license ceases to function and can
|
||||||
|
// no longer be used in any capacity
|
||||||
|
TerminationTime time.Time `json:"termination_time"`
|
||||||
|
|
||||||
|
// The product the license is valid for
|
||||||
|
Product string `json:"product"`
|
||||||
|
|
||||||
|
// License Specific Flags
|
||||||
|
Flags map[string]interface{} `json:"flags"`
|
||||||
|
|
||||||
|
// Modules is a list of the licensed enterprise modules
|
||||||
|
Modules []string `json:"modules"`
|
||||||
|
|
||||||
|
// List of features enabled by the license
|
||||||
|
Features []string `json:"features"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LicenseReply struct {
|
||||||
|
Valid bool
|
||||||
|
License *License
|
||||||
|
Warnings []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *Operator) LicenseGet(q *QueryOptions) (*LicenseReply, error) {
|
||||||
|
var reply LicenseReply
|
||||||
|
if _, err := op.c.query("/v1/operator/license", &reply, q); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return &reply, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *Operator) LicenseGetSigned(q *QueryOptions) (string, error) {
|
||||||
|
r := op.c.newRequest("GET", "/v1/operator/license")
|
||||||
|
r.params.Set("signed", "1")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LicenseReset will reset the license to the builtin one if it is still valid.
|
||||||
|
// If the builtin license is invalid, the current license stays active.
|
||||||
|
func (op *Operator) LicenseReset(opts *WriteOptions) (*LicenseReply, error) {
|
||||||
|
var reply LicenseReply
|
||||||
|
r := op.c.newRequest("DELETE", "/v1/operator/license")
|
||||||
|
r.setWriteOptions(opts)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if err := decodeBody(resp, &reply); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &reply, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *Operator) LicensePut(license string, opts *WriteOptions) (*LicenseReply, error) {
|
||||||
|
var reply LicenseReply
|
||||||
|
r := op.c.newRequest("PUT", "/v1/operator/license")
|
||||||
|
r.setWriteOptions(opts)
|
||||||
|
r.body = strings.NewReader(license)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if err := decodeBody(resp, &reply); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &reply, nil
|
||||||
|
}
|
89
vendor/github.com/hashicorp/consul/api/operator_raft.go
generated
vendored
Normal file
89
vendor/github.com/hashicorp/consul/api/operator_raft.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// RaftServer has information about a server in the Raft configuration.
|
||||||
|
type RaftServer struct {
|
||||||
|
// ID is the unique ID for the server. These are currently the same
|
||||||
|
// as the address, but they will be changed to a real GUID in a future
|
||||||
|
// release of Consul.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// Node is the node name of the server, as known by Consul, or this
|
||||||
|
// will be set to "(unknown)" otherwise.
|
||||||
|
Node string
|
||||||
|
|
||||||
|
// Address is the IP:port of the server, used for Raft communications.
|
||||||
|
Address string
|
||||||
|
|
||||||
|
// Leader is true if this server is the current cluster leader.
|
||||||
|
Leader bool
|
||||||
|
|
||||||
|
// Protocol version is the raft protocol version used by the server
|
||||||
|
ProtocolVersion string
|
||||||
|
|
||||||
|
// Voter is true if this server has a vote in the cluster. This might
|
||||||
|
// be false if the server is staging and still coming online, or if
|
||||||
|
// it's a non-voting server, which will be added in a future release of
|
||||||
|
// Consul.
|
||||||
|
Voter bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// RaftConfiguration is returned when querying for the current Raft configuration.
|
||||||
|
type RaftConfiguration struct {
|
||||||
|
// Servers has the list of servers in the Raft configuration.
|
||||||
|
Servers []*RaftServer
|
||||||
|
|
||||||
|
// Index has the Raft index of this configuration.
|
||||||
|
Index uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// RaftGetConfiguration is used to query the current Raft peer set.
|
||||||
|
func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) {
|
||||||
|
r := op.c.newRequest("GET", "/v1/operator/raft/configuration")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var out RaftConfiguration
|
||||||
|
if err := decodeBody(resp, &out); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
|
||||||
|
// quorum but no longer known to Serf or the catalog) by address in the form of
|
||||||
|
// "IP:port".
|
||||||
|
func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) error {
|
||||||
|
r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
|
||||||
|
r.params.Set("address", address)
|
||||||
|
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RaftRemovePeerByID is used to kick a stale peer (one that it in the Raft
|
||||||
|
// quorum but no longer known to Serf or the catalog) by ID.
|
||||||
|
func (op *Operator) RaftRemovePeerByID(id string, q *WriteOptions) error {
|
||||||
|
r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
|
||||||
|
r.params.Set("id", id)
|
||||||
|
|
||||||
|
_, resp, err := requireOK(op.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Body.Close()
|
||||||
|
return nil
|
||||||
|
}
|
11
vendor/github.com/hashicorp/consul/api/operator_segment.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/consul/api/operator_segment.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// SegmentList returns all the available LAN segments.
|
||||||
|
func (op *Operator) SegmentList(q *QueryOptions) ([]string, *QueryMeta, error) {
|
||||||
|
var out []string
|
||||||
|
qm, err := op.c.query("/v1/operator/segment", &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
223
vendor/github.com/hashicorp/consul/api/prepared_query.go
generated
vendored
Normal file
223
vendor/github.com/hashicorp/consul/api/prepared_query.go
generated
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// QueryDatacenterOptions sets options about how we fail over if there are no
|
||||||
|
// healthy nodes in the local datacenter.
|
||||||
|
type QueryDatacenterOptions struct {
|
||||||
|
// NearestN is set to the number of remote datacenters to try, based on
|
||||||
|
// network coordinates.
|
||||||
|
NearestN int
|
||||||
|
|
||||||
|
// Datacenters is a fixed list of datacenters to try after NearestN. We
|
||||||
|
// never try a datacenter multiple times, so those are subtracted from
|
||||||
|
// this list before proceeding.
|
||||||
|
Datacenters []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryDNSOptions controls settings when query results are served over DNS.
|
||||||
|
type QueryDNSOptions struct {
|
||||||
|
// TTL is the time to live for the served DNS results.
|
||||||
|
TTL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceQuery is used to query for a set of healthy nodes offering a specific
|
||||||
|
// service.
|
||||||
|
type ServiceQuery struct {
|
||||||
|
// Service is the service to query.
|
||||||
|
Service string
|
||||||
|
|
||||||
|
// Namespace of the service to query
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
// Near allows baking in the name of a node to automatically distance-
|
||||||
|
// sort from. The magic "_agent" value is supported, which sorts near
|
||||||
|
// the agent which initiated the request by default.
|
||||||
|
Near string
|
||||||
|
|
||||||
|
// Failover controls what we do if there are no healthy nodes in the
|
||||||
|
// local datacenter.
|
||||||
|
Failover QueryDatacenterOptions
|
||||||
|
|
||||||
|
// IgnoreCheckIDs is an optional list of health check IDs to ignore when
|
||||||
|
// considering which nodes are healthy. It is useful as an emergency measure
|
||||||
|
// to temporarily override some health check that is producing false negatives
|
||||||
|
// for example.
|
||||||
|
IgnoreCheckIDs []string
|
||||||
|
|
||||||
|
// If OnlyPassing is true then we will only include nodes with passing
|
||||||
|
// health checks (critical AND warning checks will cause a node to be
|
||||||
|
// discarded)
|
||||||
|
OnlyPassing bool
|
||||||
|
|
||||||
|
// Tags are a set of required and/or disallowed tags. If a tag is in
|
||||||
|
// this list it must be present. If the tag is preceded with "!" then
|
||||||
|
// it is disallowed.
|
||||||
|
Tags []string
|
||||||
|
|
||||||
|
// NodeMeta is a map of required node metadata fields. If a key/value
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// ServiceMeta is a map of required service metadata fields. If a key/value
|
||||||
|
// pair is in this map it must be present on the node in order for the
|
||||||
|
// service entry to be returned.
|
||||||
|
ServiceMeta 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.
|
||||||
|
type QueryTemplate struct {
|
||||||
|
// Type specifies the type of the query template. Currently only
|
||||||
|
// "name_prefix_match" is supported. This field is required.
|
||||||
|
Type string
|
||||||
|
|
||||||
|
// Regexp allows specifying a regex pattern to match against the name
|
||||||
|
// of the query being executed.
|
||||||
|
Regexp string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreparedQueryDefinition defines a complete prepared query.
|
||||||
|
type PreparedQueryDefinition struct {
|
||||||
|
// ID is this UUID-based ID for the query, always generated by Consul.
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// Name is an optional friendly name for the query supplied by the
|
||||||
|
// user. NOTE - if this feature is used then it will reduce the security
|
||||||
|
// of any read ACL associated with this query/service since this name
|
||||||
|
// can be used to locate nodes with supplying any ACL.
|
||||||
|
Name string
|
||||||
|
|
||||||
|
// Session is an optional session to tie this query's lifetime to. If
|
||||||
|
// this is omitted then the query will not expire.
|
||||||
|
Session string
|
||||||
|
|
||||||
|
// Token is the ACL token used when the query was created, and it is
|
||||||
|
// used when a query is subsequently executed. This token, or a token
|
||||||
|
// with management privileges, must be used to change the query later.
|
||||||
|
Token string
|
||||||
|
|
||||||
|
// Service defines a service query (leaving things open for other types
|
||||||
|
// later).
|
||||||
|
Service ServiceQuery
|
||||||
|
|
||||||
|
// DNS has options that control how the results of this query are
|
||||||
|
// served over DNS.
|
||||||
|
DNS QueryDNSOptions
|
||||||
|
|
||||||
|
// Template is used to pass through the arguments for creating a
|
||||||
|
// prepared query with an attached template. If a template is given,
|
||||||
|
// interpolations are possible in other struct fields.
|
||||||
|
Template QueryTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreparedQueryExecuteResponse has the results of executing a query.
|
||||||
|
type PreparedQueryExecuteResponse struct {
|
||||||
|
// Service is the service that was queried.
|
||||||
|
Service string
|
||||||
|
|
||||||
|
// Namespace of the service that was queried
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
// Nodes has the nodes that were output by the query.
|
||||||
|
Nodes []ServiceEntry
|
||||||
|
|
||||||
|
// DNS has the options for serving these results over DNS.
|
||||||
|
DNS QueryDNSOptions
|
||||||
|
|
||||||
|
// Datacenter is the datacenter that these results came from.
|
||||||
|
Datacenter string
|
||||||
|
|
||||||
|
// Failovers is a count of how many times we had to query a remote
|
||||||
|
// datacenter.
|
||||||
|
Failovers int
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreparedQuery can be used to query the prepared query endpoints.
|
||||||
|
type PreparedQuery struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreparedQuery returns a handle to the prepared query endpoints.
|
||||||
|
func (c *Client) PreparedQuery() *PreparedQuery {
|
||||||
|
return &PreparedQuery{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create makes a new prepared query. The ID of the new query is returned.
|
||||||
|
func (c *PreparedQuery) Create(query *PreparedQueryDefinition, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
r := c.c.newRequest("POST", "/v1/query")
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
r.obj = query
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update makes updates to an existing prepared query.
|
||||||
|
func (c *PreparedQuery) Update(query *PreparedQueryDefinition, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
return c.c.write("/v1/query/"+query.ID, query, nil, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List is used to fetch all the prepared queries (always requires a management
|
||||||
|
// token).
|
||||||
|
func (c *PreparedQuery) List(q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) {
|
||||||
|
var out []*PreparedQueryDefinition
|
||||||
|
qm, err := c.c.query("/v1/query", &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get is used to fetch a specific prepared query.
|
||||||
|
func (c *PreparedQuery) Get(queryID string, q *QueryOptions) ([]*PreparedQueryDefinition, *QueryMeta, error) {
|
||||||
|
var out []*PreparedQueryDefinition
|
||||||
|
qm, err := c.c.query("/v1/query/"+queryID, &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete is used to delete a specific prepared query.
|
||||||
|
func (c *PreparedQuery) Delete(queryID string, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
r := c.c.newRequest("DELETE", "/v1/query/"+queryID)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute is used to execute a specific prepared query. You can execute using
|
||||||
|
// a query ID or name.
|
||||||
|
func (c *PreparedQuery) Execute(queryIDOrName string, q *QueryOptions) (*PreparedQueryExecuteResponse, *QueryMeta, error) {
|
||||||
|
var out *PreparedQueryExecuteResponse
|
||||||
|
qm, err := c.c.query("/v1/query/"+queryIDOrName+"/execute", &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return out, qm, nil
|
||||||
|
}
|
24
vendor/github.com/hashicorp/consul/api/raw.go
generated
vendored
Normal file
24
vendor/github.com/hashicorp/consul/api/raw.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Raw can be used to do raw queries against custom endpoints
|
||||||
|
type Raw struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raw returns a handle to query endpoints
|
||||||
|
func (c *Client) Raw() *Raw {
|
||||||
|
return &Raw{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query is used to do a GET request against an endpoint
|
||||||
|
// and deserialize the response into an interface using
|
||||||
|
// standard Consul conventions.
|
||||||
|
func (raw *Raw) Query(endpoint string, out interface{}, q *QueryOptions) (*QueryMeta, error) {
|
||||||
|
return raw.c.query(endpoint, out, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is used to do a PUT request against an endpoint
|
||||||
|
// and serialize/deserialized using the standard Consul conventions.
|
||||||
|
func (raw *Raw) Write(endpoint string, in, out interface{}, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
return raw.c.write(endpoint, in, out, q)
|
||||||
|
}
|
530
vendor/github.com/hashicorp/consul/api/semaphore.go
generated
vendored
Normal file
530
vendor/github.com/hashicorp/consul/api/semaphore.go
generated
vendored
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultSemaphoreSessionName is the Session Name we assign if none is provided
|
||||||
|
DefaultSemaphoreSessionName = "Consul API Semaphore"
|
||||||
|
|
||||||
|
// DefaultSemaphoreSessionTTL is the default session TTL if no Session is provided
|
||||||
|
// when creating a new Semaphore. This is used because we do not have another
|
||||||
|
// other check to depend upon.
|
||||||
|
DefaultSemaphoreSessionTTL = "15s"
|
||||||
|
|
||||||
|
// DefaultSemaphoreWaitTime is how long we block for at a time to check if semaphore
|
||||||
|
// acquisition is possible. This affects the minimum time it takes to cancel
|
||||||
|
// a Semaphore acquisition.
|
||||||
|
DefaultSemaphoreWaitTime = 15 * time.Second
|
||||||
|
|
||||||
|
// DefaultSemaphoreKey is the key used within the prefix to
|
||||||
|
// use for coordination between all the contenders.
|
||||||
|
DefaultSemaphoreKey = ".lock"
|
||||||
|
|
||||||
|
// SemaphoreFlagValue is a magic flag we set to indicate a key
|
||||||
|
// is being used for a semaphore. It is used to detect a potential
|
||||||
|
// conflict with a lock.
|
||||||
|
SemaphoreFlagValue = 0xe0f69a2baa414de0
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrSemaphoreHeld is returned if we attempt to double lock
|
||||||
|
ErrSemaphoreHeld = fmt.Errorf("Semaphore already held")
|
||||||
|
|
||||||
|
// ErrSemaphoreNotHeld is returned if we attempt to unlock a semaphore
|
||||||
|
// that we do not hold.
|
||||||
|
ErrSemaphoreNotHeld = fmt.Errorf("Semaphore not held")
|
||||||
|
|
||||||
|
// ErrSemaphoreInUse is returned if we attempt to destroy a semaphore
|
||||||
|
// that is in use.
|
||||||
|
ErrSemaphoreInUse = fmt.Errorf("Semaphore in use")
|
||||||
|
|
||||||
|
// ErrSemaphoreConflict is returned if the flags on a key
|
||||||
|
// used for a semaphore do not match expectation
|
||||||
|
ErrSemaphoreConflict = fmt.Errorf("Existing key does not match semaphore use")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Semaphore is used to implement a distributed semaphore
|
||||||
|
// using the Consul KV primitives.
|
||||||
|
type Semaphore struct {
|
||||||
|
c *Client
|
||||||
|
opts *SemaphoreOptions
|
||||||
|
|
||||||
|
isHeld bool
|
||||||
|
sessionRenew chan struct{}
|
||||||
|
lockSession string
|
||||||
|
l sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemaphoreOptions is used to parameterize the Semaphore
|
||||||
|
type SemaphoreOptions struct {
|
||||||
|
Prefix string // Must be set and have write permissions
|
||||||
|
Limit int // Must be set, and be positive
|
||||||
|
Value []byte // Optional, value to associate with the contender entry
|
||||||
|
Session string // Optional, created if not specified
|
||||||
|
SessionName string // Optional, defaults to DefaultLockSessionName
|
||||||
|
SessionTTL string // Optional, defaults to DefaultLockSessionTTL
|
||||||
|
MonitorRetries int // Optional, defaults to 0 which means no retries
|
||||||
|
MonitorRetryTime time.Duration // Optional, defaults to DefaultMonitorRetryTime
|
||||||
|
SemaphoreWaitTime time.Duration // Optional, defaults to DefaultSemaphoreWaitTime
|
||||||
|
SemaphoreTryOnce bool // Optional, defaults to false which means try forever
|
||||||
|
Namespace string `json:",omitempty"` // Optional, defaults to API client config, namespace of ACL token, or "default" namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
// semaphoreLock is written under the DefaultSemaphoreKey and
|
||||||
|
// is used to coordinate between all the contenders.
|
||||||
|
type semaphoreLock struct {
|
||||||
|
// Limit is the integer limit of holders. This is used to
|
||||||
|
// verify that all the holders agree on the value.
|
||||||
|
Limit int
|
||||||
|
|
||||||
|
// Holders is a list of all the semaphore holders.
|
||||||
|
// It maps the session ID to true. It is used as a set effectively.
|
||||||
|
Holders map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemaphorePrefix is used to created a Semaphore which will operate
|
||||||
|
// at the given KV prefix and uses the given limit for the semaphore.
|
||||||
|
// The prefix must have write privileges, and the limit must be agreed
|
||||||
|
// upon by all contenders.
|
||||||
|
func (c *Client) SemaphorePrefix(prefix string, limit int) (*Semaphore, error) {
|
||||||
|
opts := &SemaphoreOptions{
|
||||||
|
Prefix: prefix,
|
||||||
|
Limit: limit,
|
||||||
|
}
|
||||||
|
return c.SemaphoreOpts(opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SemaphoreOpts is used to create a Semaphore with the given options.
|
||||||
|
// The prefix must have write privileges, and the limit must be agreed
|
||||||
|
// upon by all contenders. If a Session is not provided, one will be created.
|
||||||
|
func (c *Client) SemaphoreOpts(opts *SemaphoreOptions) (*Semaphore, error) {
|
||||||
|
if opts.Prefix == "" {
|
||||||
|
return nil, fmt.Errorf("missing prefix")
|
||||||
|
}
|
||||||
|
if opts.Limit <= 0 {
|
||||||
|
return nil, fmt.Errorf("semaphore limit must be positive")
|
||||||
|
}
|
||||||
|
if opts.SessionName == "" {
|
||||||
|
opts.SessionName = DefaultSemaphoreSessionName
|
||||||
|
}
|
||||||
|
if opts.SessionTTL == "" {
|
||||||
|
opts.SessionTTL = DefaultSemaphoreSessionTTL
|
||||||
|
} else {
|
||||||
|
if _, err := time.ParseDuration(opts.SessionTTL); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid SessionTTL: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if opts.MonitorRetryTime == 0 {
|
||||||
|
opts.MonitorRetryTime = DefaultMonitorRetryTime
|
||||||
|
}
|
||||||
|
if opts.SemaphoreWaitTime == 0 {
|
||||||
|
opts.SemaphoreWaitTime = DefaultSemaphoreWaitTime
|
||||||
|
}
|
||||||
|
s := &Semaphore{
|
||||||
|
c: c,
|
||||||
|
opts: opts,
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire attempts to reserve a slot in the semaphore, blocking until
|
||||||
|
// success, interrupted via the stopCh or an error is encountered.
|
||||||
|
// Providing a non-nil stopCh can be used to abort the attempt.
|
||||||
|
// On success, a channel is returned that represents our slot.
|
||||||
|
// This channel could be closed at any time due to session invalidation,
|
||||||
|
// communication errors, operator intervention, etc. It is NOT safe to
|
||||||
|
// assume that the slot is held until Release() unless the Session is specifically
|
||||||
|
// created without any associated health checks. By default Consul sessions
|
||||||
|
// prefer liveness over safety and an application must be able to handle
|
||||||
|
// the session being lost.
|
||||||
|
func (s *Semaphore) Acquire(stopCh <-chan struct{}) (<-chan struct{}, error) {
|
||||||
|
// Hold the lock as we try to acquire
|
||||||
|
s.l.Lock()
|
||||||
|
defer s.l.Unlock()
|
||||||
|
|
||||||
|
// Check if we already hold the semaphore
|
||||||
|
if s.isHeld {
|
||||||
|
return nil, ErrSemaphoreHeld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we need to create a session first
|
||||||
|
s.lockSession = s.opts.Session
|
||||||
|
if s.lockSession == "" {
|
||||||
|
sess, err := s.createSession()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create session: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.sessionRenew = make(chan struct{})
|
||||||
|
s.lockSession = sess
|
||||||
|
session := s.c.Session()
|
||||||
|
go session.RenewPeriodic(s.opts.SessionTTL, sess, nil, s.sessionRenew)
|
||||||
|
|
||||||
|
// If we fail to acquire the lock, cleanup the session
|
||||||
|
defer func() {
|
||||||
|
if !s.isHeld {
|
||||||
|
close(s.sessionRenew)
|
||||||
|
s.sessionRenew = nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the contender entry
|
||||||
|
kv := s.c.KV()
|
||||||
|
wOpts := WriteOptions{Namespace: s.opts.Namespace}
|
||||||
|
|
||||||
|
made, _, err := kv.Acquire(s.contenderEntry(s.lockSession), &wOpts)
|
||||||
|
if err != nil || !made {
|
||||||
|
return nil, fmt.Errorf("failed to make contender entry: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the query options
|
||||||
|
qOpts := QueryOptions{
|
||||||
|
WaitTime: s.opts.SemaphoreWaitTime,
|
||||||
|
Namespace: s.opts.Namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
attempts := 0
|
||||||
|
WAIT:
|
||||||
|
// Check if we should quit
|
||||||
|
select {
|
||||||
|
case <-stopCh:
|
||||||
|
return nil, nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the one-shot mode.
|
||||||
|
if s.opts.SemaphoreTryOnce && attempts > 0 {
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
if elapsed > s.opts.SemaphoreWaitTime {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query wait time should not exceed the semaphore wait time
|
||||||
|
qOpts.WaitTime = s.opts.SemaphoreWaitTime - elapsed
|
||||||
|
}
|
||||||
|
attempts++
|
||||||
|
|
||||||
|
// Read the prefix
|
||||||
|
pairs, meta, err := kv.List(s.opts.Prefix, &qOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read prefix: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the lock
|
||||||
|
lockPair := s.findLock(pairs)
|
||||||
|
if lockPair.Flags != SemaphoreFlagValue {
|
||||||
|
return nil, ErrSemaphoreConflict
|
||||||
|
}
|
||||||
|
lock, err := s.decodeLock(lockPair)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify we agree with the limit
|
||||||
|
if lock.Limit != s.opts.Limit {
|
||||||
|
return nil, fmt.Errorf("semaphore limit conflict (lock: %d, local: %d)",
|
||||||
|
lock.Limit, s.opts.Limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune the dead holders
|
||||||
|
s.pruneDeadHolders(lock, pairs)
|
||||||
|
|
||||||
|
// Check if the lock is held
|
||||||
|
if len(lock.Holders) >= lock.Limit {
|
||||||
|
qOpts.WaitIndex = meta.LastIndex
|
||||||
|
goto WAIT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new lock with us as a holder
|
||||||
|
lock.Holders[s.lockSession] = true
|
||||||
|
newLock, err := s.encodeLock(lock, lockPair.ModifyIndex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt the acquisition
|
||||||
|
didSet, _, err := kv.CAS(newLock, &wOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to update lock: %v", err)
|
||||||
|
}
|
||||||
|
if !didSet {
|
||||||
|
// Update failed, could have been a race with another contender,
|
||||||
|
// retry the operation
|
||||||
|
goto WAIT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch to ensure we maintain ownership of the slot
|
||||||
|
lockCh := make(chan struct{})
|
||||||
|
go s.monitorLock(s.lockSession, lockCh)
|
||||||
|
|
||||||
|
// Set that we own the lock
|
||||||
|
s.isHeld = true
|
||||||
|
|
||||||
|
// Acquired! All done
|
||||||
|
return lockCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release is used to voluntarily give up our semaphore slot. It is
|
||||||
|
// an error to call this if the semaphore has not been acquired.
|
||||||
|
func (s *Semaphore) Release() error {
|
||||||
|
// Hold the lock as we try to release
|
||||||
|
s.l.Lock()
|
||||||
|
defer s.l.Unlock()
|
||||||
|
|
||||||
|
// Ensure the lock is actually held
|
||||||
|
if !s.isHeld {
|
||||||
|
return ErrSemaphoreNotHeld
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set that we no longer own the lock
|
||||||
|
s.isHeld = false
|
||||||
|
|
||||||
|
// Stop the session renew
|
||||||
|
if s.sessionRenew != nil {
|
||||||
|
defer func() {
|
||||||
|
close(s.sessionRenew)
|
||||||
|
s.sessionRenew = nil
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get and clear the lock session
|
||||||
|
lockSession := s.lockSession
|
||||||
|
s.lockSession = ""
|
||||||
|
|
||||||
|
// Remove ourselves as a lock holder
|
||||||
|
kv := s.c.KV()
|
||||||
|
key := path.Join(s.opts.Prefix, DefaultSemaphoreKey)
|
||||||
|
|
||||||
|
wOpts := WriteOptions{Namespace: s.opts.Namespace}
|
||||||
|
qOpts := QueryOptions{Namespace: s.opts.Namespace}
|
||||||
|
|
||||||
|
READ:
|
||||||
|
pair, _, err := kv.Get(key, &qOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pair == nil {
|
||||||
|
pair = &KVPair{}
|
||||||
|
}
|
||||||
|
lock, err := s.decodeLock(pair)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new lock without us as a holder
|
||||||
|
if _, ok := lock.Holders[lockSession]; ok {
|
||||||
|
delete(lock.Holders, lockSession)
|
||||||
|
newLock, err := s.encodeLock(lock, pair.ModifyIndex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the locks
|
||||||
|
didSet, _, err := kv.CAS(newLock, &wOpts)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to update lock: %v", err)
|
||||||
|
}
|
||||||
|
if !didSet {
|
||||||
|
goto READ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the contender entry
|
||||||
|
contenderKey := path.Join(s.opts.Prefix, lockSession)
|
||||||
|
if _, err := kv.Delete(contenderKey, &wOpts); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy is used to cleanup the semaphore entry. It is not necessary
|
||||||
|
// to invoke. It will fail if the semaphore is in use.
|
||||||
|
func (s *Semaphore) Destroy() error {
|
||||||
|
// Hold the lock as we try to acquire
|
||||||
|
s.l.Lock()
|
||||||
|
defer s.l.Unlock()
|
||||||
|
|
||||||
|
// Check if we already hold the semaphore
|
||||||
|
if s.isHeld {
|
||||||
|
return ErrSemaphoreHeld
|
||||||
|
}
|
||||||
|
|
||||||
|
// List for the semaphore
|
||||||
|
kv := s.c.KV()
|
||||||
|
|
||||||
|
q := QueryOptions{Namespace: s.opts.Namespace}
|
||||||
|
pairs, _, err := kv.List(s.opts.Prefix, &q)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read prefix: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the lock pair, bail if it doesn't exist
|
||||||
|
lockPair := s.findLock(pairs)
|
||||||
|
if lockPair.ModifyIndex == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if lockPair.Flags != SemaphoreFlagValue {
|
||||||
|
return ErrSemaphoreConflict
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the lock
|
||||||
|
lock, err := s.decodeLock(lockPair)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune the dead holders
|
||||||
|
s.pruneDeadHolders(lock, pairs)
|
||||||
|
|
||||||
|
// Check if there are any holders
|
||||||
|
if len(lock.Holders) > 0 {
|
||||||
|
return ErrSemaphoreInUse
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt the delete
|
||||||
|
w := WriteOptions{Namespace: s.opts.Namespace}
|
||||||
|
didRemove, _, err := kv.DeleteCAS(lockPair, &w)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to remove semaphore: %v", err)
|
||||||
|
}
|
||||||
|
if !didRemove {
|
||||||
|
return ErrSemaphoreInUse
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createSession is used to create a new managed session
|
||||||
|
func (s *Semaphore) createSession() (string, error) {
|
||||||
|
session := s.c.Session()
|
||||||
|
se := &SessionEntry{
|
||||||
|
Name: s.opts.SessionName,
|
||||||
|
TTL: s.opts.SessionTTL,
|
||||||
|
Behavior: SessionBehaviorDelete,
|
||||||
|
}
|
||||||
|
|
||||||
|
w := WriteOptions{Namespace: s.opts.Namespace}
|
||||||
|
id, _, err := session.Create(se, &w)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// contenderEntry returns a formatted KVPair for the contender
|
||||||
|
func (s *Semaphore) contenderEntry(session string) *KVPair {
|
||||||
|
return &KVPair{
|
||||||
|
Key: path.Join(s.opts.Prefix, session),
|
||||||
|
Value: s.opts.Value,
|
||||||
|
Session: session,
|
||||||
|
Flags: SemaphoreFlagValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findLock is used to find the KV Pair which is used for coordination
|
||||||
|
func (s *Semaphore) findLock(pairs KVPairs) *KVPair {
|
||||||
|
key := path.Join(s.opts.Prefix, DefaultSemaphoreKey)
|
||||||
|
for _, pair := range pairs {
|
||||||
|
if pair.Key == key {
|
||||||
|
return pair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &KVPair{Flags: SemaphoreFlagValue}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeLock is used to decode a semaphoreLock from an
|
||||||
|
// entry in Consul
|
||||||
|
func (s *Semaphore) decodeLock(pair *KVPair) (*semaphoreLock, error) {
|
||||||
|
// Handle if there is no lock
|
||||||
|
if pair == nil || pair.Value == nil {
|
||||||
|
return &semaphoreLock{
|
||||||
|
Limit: s.opts.Limit,
|
||||||
|
Holders: make(map[string]bool),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
l := &semaphoreLock{}
|
||||||
|
if err := json.Unmarshal(pair.Value, l); err != nil {
|
||||||
|
return nil, fmt.Errorf("lock decoding failed: %v", err)
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeLock is used to encode a semaphoreLock into a KVPair
|
||||||
|
// that can be PUT
|
||||||
|
func (s *Semaphore) encodeLock(l *semaphoreLock, oldIndex uint64) (*KVPair, error) {
|
||||||
|
enc, err := json.Marshal(l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("lock encoding failed: %v", err)
|
||||||
|
}
|
||||||
|
pair := &KVPair{
|
||||||
|
Key: path.Join(s.opts.Prefix, DefaultSemaphoreKey),
|
||||||
|
Value: enc,
|
||||||
|
Flags: SemaphoreFlagValue,
|
||||||
|
ModifyIndex: oldIndex,
|
||||||
|
}
|
||||||
|
return pair, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pruneDeadHolders is used to remove all the dead lock holders
|
||||||
|
func (s *Semaphore) pruneDeadHolders(lock *semaphoreLock, pairs KVPairs) {
|
||||||
|
// Gather all the live holders
|
||||||
|
alive := make(map[string]struct{}, len(pairs))
|
||||||
|
for _, pair := range pairs {
|
||||||
|
if pair.Session != "" {
|
||||||
|
alive[pair.Session] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any holders that are dead
|
||||||
|
for holder := range lock.Holders {
|
||||||
|
if _, ok := alive[holder]; !ok {
|
||||||
|
delete(lock.Holders, holder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// monitorLock is a long running routine to monitor a semaphore ownership
|
||||||
|
// It closes the stopCh if we lose our slot.
|
||||||
|
func (s *Semaphore) monitorLock(session string, stopCh chan struct{}) {
|
||||||
|
defer close(stopCh)
|
||||||
|
kv := s.c.KV()
|
||||||
|
opts := QueryOptions{
|
||||||
|
RequireConsistent: true,
|
||||||
|
Namespace: s.opts.Namespace,
|
||||||
|
}
|
||||||
|
WAIT:
|
||||||
|
retries := s.opts.MonitorRetries
|
||||||
|
RETRY:
|
||||||
|
pairs, meta, err := kv.List(s.opts.Prefix, &opts)
|
||||||
|
if err != nil {
|
||||||
|
// If configured we can try to ride out a brief Consul unavailability
|
||||||
|
// by doing retries. Note that we have to attempt the retry in a non-
|
||||||
|
// blocking fashion so that we have a clean place to reset the retry
|
||||||
|
// counter if service is restored.
|
||||||
|
if retries > 0 && IsRetryableError(err) {
|
||||||
|
time.Sleep(s.opts.MonitorRetryTime)
|
||||||
|
retries--
|
||||||
|
opts.WaitIndex = 0
|
||||||
|
goto RETRY
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lockPair := s.findLock(pairs)
|
||||||
|
lock, err := s.decodeLock(lockPair)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.pruneDeadHolders(lock, pairs)
|
||||||
|
if _, ok := lock.Holders[session]; ok {
|
||||||
|
opts.WaitIndex = meta.LastIndex
|
||||||
|
goto WAIT
|
||||||
|
}
|
||||||
|
}
|
243
vendor/github.com/hashicorp/consul/api/session.go
generated
vendored
Normal file
243
vendor/github.com/hashicorp/consul/api/session.go
generated
vendored
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SessionBehaviorRelease is the default behavior and causes
|
||||||
|
// all associated locks to be released on session invalidation.
|
||||||
|
SessionBehaviorRelease = "release"
|
||||||
|
|
||||||
|
// SessionBehaviorDelete is new in Consul 0.5 and changes the
|
||||||
|
// behavior to delete all associated locks on session invalidation.
|
||||||
|
// It can be used in a way similar to Ephemeral Nodes in ZooKeeper.
|
||||||
|
SessionBehaviorDelete = "delete"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrSessionExpired = errors.New("session expired")
|
||||||
|
|
||||||
|
// SessionEntry represents a session in consul
|
||||||
|
type SessionEntry struct {
|
||||||
|
CreateIndex uint64
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Node string
|
||||||
|
LockDelay time.Duration
|
||||||
|
Behavior string
|
||||||
|
TTL string
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
|
||||||
|
// Deprecated for Consul Enterprise in v1.7.0.
|
||||||
|
Checks []string
|
||||||
|
|
||||||
|
// NodeChecks and ServiceChecks are new in Consul 1.7.0.
|
||||||
|
// When associating checks with sessions, namespaces can be specified for service checks.
|
||||||
|
NodeChecks []string
|
||||||
|
ServiceChecks []ServiceCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceCheck struct {
|
||||||
|
ID string
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Session can be used to query the Session endpoints
|
||||||
|
type Session struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Session returns a handle to the session endpoints
|
||||||
|
func (c *Client) Session() *Session {
|
||||||
|
return &Session{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateNoChecks is like Create but is used specifically to create
|
||||||
|
// a session with no associated health checks.
|
||||||
|
func (s *Session) CreateNoChecks(se *SessionEntry, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
body := make(map[string]interface{})
|
||||||
|
body["NodeChecks"] = []string{}
|
||||||
|
if se != nil {
|
||||||
|
if se.Name != "" {
|
||||||
|
body["Name"] = se.Name
|
||||||
|
}
|
||||||
|
if se.Node != "" {
|
||||||
|
body["Node"] = se.Node
|
||||||
|
}
|
||||||
|
if se.LockDelay != 0 {
|
||||||
|
body["LockDelay"] = durToMsec(se.LockDelay)
|
||||||
|
}
|
||||||
|
if se.Behavior != "" {
|
||||||
|
body["Behavior"] = se.Behavior
|
||||||
|
}
|
||||||
|
if se.TTL != "" {
|
||||||
|
body["TTL"] = se.TTL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.create(body, q)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create makes a new session. Providing a session entry can
|
||||||
|
// customize the session. It can also be nil to use defaults.
|
||||||
|
func (s *Session) Create(se *SessionEntry, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
var obj interface{}
|
||||||
|
if se != nil {
|
||||||
|
body := make(map[string]interface{})
|
||||||
|
obj = body
|
||||||
|
if se.Name != "" {
|
||||||
|
body["Name"] = se.Name
|
||||||
|
}
|
||||||
|
if se.Node != "" {
|
||||||
|
body["Node"] = se.Node
|
||||||
|
}
|
||||||
|
if se.LockDelay != 0 {
|
||||||
|
body["LockDelay"] = durToMsec(se.LockDelay)
|
||||||
|
}
|
||||||
|
if len(se.Checks) > 0 {
|
||||||
|
body["Checks"] = se.Checks
|
||||||
|
}
|
||||||
|
if len(se.NodeChecks) > 0 {
|
||||||
|
body["NodeChecks"] = se.NodeChecks
|
||||||
|
}
|
||||||
|
if len(se.ServiceChecks) > 0 {
|
||||||
|
body["ServiceChecks"] = se.ServiceChecks
|
||||||
|
}
|
||||||
|
if se.Behavior != "" {
|
||||||
|
body["Behavior"] = se.Behavior
|
||||||
|
}
|
||||||
|
if se.TTL != "" {
|
||||||
|
body["TTL"] = se.TTL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.create(obj, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) create(obj interface{}, q *WriteOptions) (string, *WriteMeta, error) {
|
||||||
|
var out struct{ ID string }
|
||||||
|
wm, err := s.c.write("/v1/session/create", obj, &out, q)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
return out.ID, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy invalidates a given session
|
||||||
|
func (s *Session) Destroy(id string, q *WriteOptions) (*WriteMeta, error) {
|
||||||
|
wm, err := s.c.write("/v1/session/destroy/"+id, nil, nil, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renew renews the TTL on a given session
|
||||||
|
func (s *Session) Renew(id string, q *WriteOptions) (*SessionEntry, *WriteMeta, error) {
|
||||||
|
r := s.c.newRequest("PUT", "/v1/session/renew/"+id)
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
rtt, resp, err := s.c.doRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
wm := &WriteMeta{RequestTime: rtt}
|
||||||
|
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
return nil, wm, nil
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
return nil, nil, fmt.Errorf("Unexpected response code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
var entries []*SessionEntry
|
||||||
|
if err := decodeBody(resp, &entries); err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Failed to read response: %v", err)
|
||||||
|
}
|
||||||
|
if len(entries) > 0 {
|
||||||
|
return entries[0], wm, nil
|
||||||
|
}
|
||||||
|
return nil, wm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenewPeriodic is used to periodically invoke Session.Renew on a
|
||||||
|
// session until a doneCh is closed. This is meant to be used in a long running
|
||||||
|
// goroutine to ensure a session stays valid.
|
||||||
|
func (s *Session) RenewPeriodic(initialTTL string, id string, q *WriteOptions, doneCh <-chan struct{}) error {
|
||||||
|
ctx := q.Context()
|
||||||
|
|
||||||
|
ttl, err := time.ParseDuration(initialTTL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
waitDur := ttl / 2
|
||||||
|
lastRenewTime := time.Now()
|
||||||
|
var lastErr error
|
||||||
|
for {
|
||||||
|
if time.Since(lastRenewTime) > ttl {
|
||||||
|
return lastErr
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-time.After(waitDur):
|
||||||
|
entry, _, err := s.Renew(id, q)
|
||||||
|
if err != nil {
|
||||||
|
waitDur = time.Second
|
||||||
|
lastErr = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if entry == nil {
|
||||||
|
return ErrSessionExpired
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the server updating the TTL
|
||||||
|
ttl, _ = time.ParseDuration(entry.TTL)
|
||||||
|
waitDur = ttl / 2
|
||||||
|
lastRenewTime = time.Now()
|
||||||
|
|
||||||
|
case <-doneCh:
|
||||||
|
// Attempt a session destroy
|
||||||
|
s.Destroy(id, q)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case <-ctx.Done():
|
||||||
|
// Bail immediately since attempting the destroy would
|
||||||
|
// use the canceled context in q, which would just bail.
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info looks up a single session
|
||||||
|
func (s *Session) Info(id string, q *QueryOptions) (*SessionEntry, *QueryMeta, error) {
|
||||||
|
var entries []*SessionEntry
|
||||||
|
qm, err := s.c.query("/v1/session/info/"+id, &entries, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if len(entries) > 0 {
|
||||||
|
return entries[0], qm, nil
|
||||||
|
}
|
||||||
|
return nil, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List gets sessions for a node
|
||||||
|
func (s *Session) Node(node string, q *QueryOptions) ([]*SessionEntry, *QueryMeta, error) {
|
||||||
|
var entries []*SessionEntry
|
||||||
|
qm, err := s.c.query("/v1/session/node/"+node, &entries, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return entries, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// List gets all active sessions
|
||||||
|
func (s *Session) List(q *QueryOptions) ([]*SessionEntry, *QueryMeta, error) {
|
||||||
|
var entries []*SessionEntry
|
||||||
|
qm, err := s.c.query("/v1/session/list", &entries, q)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return entries, qm, nil
|
||||||
|
}
|
47
vendor/github.com/hashicorp/consul/api/snapshot.go
generated
vendored
Normal file
47
vendor/github.com/hashicorp/consul/api/snapshot.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Snapshot can be used to query the /v1/snapshot endpoint to take snapshots of
|
||||||
|
// Consul's internal state and restore snapshots for disaster recovery.
|
||||||
|
type Snapshot struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snapshot returns a handle that exposes the snapshot endpoints.
|
||||||
|
func (c *Client) Snapshot() *Snapshot {
|
||||||
|
return &Snapshot{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save requests a new snapshot and provides an io.ReadCloser with the snapshot
|
||||||
|
// data to save. If this doesn't return an error, then it's the responsibility
|
||||||
|
// of the caller to close it. Only a subset of the QueryOptions are supported:
|
||||||
|
// Datacenter, AllowStale, and Token.
|
||||||
|
func (s *Snapshot) Save(q *QueryOptions) (io.ReadCloser, *QueryMeta, error) {
|
||||||
|
r := s.c.newRequest("GET", "/v1/snapshot")
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
|
||||||
|
rtt, resp, err := requireOK(s.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
qm := &QueryMeta{}
|
||||||
|
parseQueryMeta(resp, qm)
|
||||||
|
qm.RequestTime = rtt
|
||||||
|
return resp.Body, qm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore streams in an existing snapshot and attempts to restore it.
|
||||||
|
func (s *Snapshot) Restore(q *WriteOptions, in io.Reader) error {
|
||||||
|
r := s.c.newRequest("PUT", "/v1/snapshot")
|
||||||
|
r.body = in
|
||||||
|
r.setWriteOptions(q)
|
||||||
|
_, _, err := requireOK(s.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
61
vendor/github.com/hashicorp/consul/api/status.go
generated
vendored
Normal file
61
vendor/github.com/hashicorp/consul/api/status.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Status can be used to query the Status endpoints
|
||||||
|
type Status struct {
|
||||||
|
c *Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns a handle to the status endpoints
|
||||||
|
func (c *Client) Status() *Status {
|
||||||
|
return &Status{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leader is used to query for a known leader
|
||||||
|
func (s *Status) LeaderWithQueryOptions(q *QueryOptions) (string, error) {
|
||||||
|
r := s.c.newRequest("GET", "/v1/status/leader")
|
||||||
|
|
||||||
|
if q != nil {
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp, err := requireOK(s.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var leader string
|
||||||
|
if err := decodeBody(resp, &leader); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return leader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Status) Leader() (string, error) {
|
||||||
|
return s.LeaderWithQueryOptions(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peers is used to query for a known raft peers
|
||||||
|
func (s *Status) PeersWithQueryOptions(q *QueryOptions) ([]string, error) {
|
||||||
|
r := s.c.newRequest("GET", "/v1/status/peers")
|
||||||
|
|
||||||
|
if q != nil {
|
||||||
|
r.setQueryOptions(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, resp, err := requireOK(s.c.doRequest(r))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var peers []string
|
||||||
|
if err := decodeBody(resp, &peers); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return peers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Status) Peers() ([]string, error) {
|
||||||
|
return s.PeersWithQueryOptions(nil)
|
||||||
|
}
|
244
vendor/github.com/hashicorp/consul/api/txn.go
generated
vendored
Normal file
244
vendor/github.com/hashicorp/consul/api/txn.go
generated
vendored
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
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
|
||||||
|
Namespace string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionOp constants give possible operations available in a transaction.
|
||||||
|
type SessionOp string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SessionDelete SessionOp = "delete"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SessionTxnOp defines a single operation inside a transaction.
|
||||||
|
type SessionTxnOp struct {
|
||||||
|
Verb SessionOp
|
||||||
|
Session Session
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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())
|
||||||
|
}
|
321
vendor/github.com/hashicorp/consul/api/watch/funcs.go
generated
vendored
Normal file
321
vendor/github.com/hashicorp/consul/api/watch/funcs.go
generated
vendored
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
package watch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
consulapi "github.com/hashicorp/consul/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
// watchFactory is a function that can create a new WatchFunc
|
||||||
|
// from a parameter configuration
|
||||||
|
type watchFactory func(params map[string]interface{}) (WatcherFunc, error)
|
||||||
|
|
||||||
|
// watchFuncFactory maps each type to a factory function
|
||||||
|
var watchFuncFactory map[string]watchFactory
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
watchFuncFactory = map[string]watchFactory{
|
||||||
|
"key": keyWatch,
|
||||||
|
"keyprefix": keyPrefixWatch,
|
||||||
|
"services": servicesWatch,
|
||||||
|
"nodes": nodesWatch,
|
||||||
|
"service": serviceWatch,
|
||||||
|
"checks": checksWatch,
|
||||||
|
"event": eventWatch,
|
||||||
|
"connect_roots": connectRootsWatch,
|
||||||
|
"connect_leaf": connectLeafWatch,
|
||||||
|
"agent_service": agentServiceWatch,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyWatch is used to return a key watching function
|
||||||
|
func keyWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
stale := false
|
||||||
|
if err := assignValueBool(params, "stale", &stale); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var key string
|
||||||
|
if err := assignValue(params, "key", &key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if key == "" {
|
||||||
|
return nil, fmt.Errorf("Must specify a single key to watch")
|
||||||
|
}
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
kv := p.client.KV()
|
||||||
|
opts := makeQueryOptionsWithContext(p, stale)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
pair, meta, err := kv.Get(key, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if pair == nil {
|
||||||
|
return WaitIndexVal(meta.LastIndex), nil, err
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), pair, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyPrefixWatch is used to return a key prefix watching function
|
||||||
|
func keyPrefixWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
stale := false
|
||||||
|
if err := assignValueBool(params, "stale", &stale); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefix string
|
||||||
|
if err := assignValue(params, "prefix", &prefix); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if prefix == "" {
|
||||||
|
return nil, fmt.Errorf("Must specify a single prefix to watch")
|
||||||
|
}
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
kv := p.client.KV()
|
||||||
|
opts := makeQueryOptionsWithContext(p, stale)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
pairs, meta, err := kv.List(prefix, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), pairs, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// servicesWatch is used to watch the list of available services
|
||||||
|
func servicesWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
stale := false
|
||||||
|
if err := assignValueBool(params, "stale", &stale); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
catalog := p.client.Catalog()
|
||||||
|
opts := makeQueryOptionsWithContext(p, stale)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
services, meta, err := catalog.Services(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), services, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodesWatch is used to watch the list of available nodes
|
||||||
|
func nodesWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
stale := false
|
||||||
|
if err := assignValueBool(params, "stale", &stale); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
catalog := p.client.Catalog()
|
||||||
|
opts := makeQueryOptionsWithContext(p, stale)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
nodes, meta, err := catalog.Nodes(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), nodes, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// serviceWatch is used to watch a specific service for changes
|
||||||
|
func serviceWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
stale := false
|
||||||
|
if err := assignValueBool(params, "stale", &stale); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
service string
|
||||||
|
tags []string
|
||||||
|
)
|
||||||
|
if err := assignValue(params, "service", &service); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if service == "" {
|
||||||
|
return nil, fmt.Errorf("Must specify a single service to watch")
|
||||||
|
}
|
||||||
|
if err := assignValueStringSlice(params, "tag", &tags); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
passingOnly := false
|
||||||
|
if err := assignValueBool(params, "passingonly", &passingOnly); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
health := p.client.Health()
|
||||||
|
opts := makeQueryOptionsWithContext(p, stale)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
nodes, meta, err := health.ServiceMultipleTags(service, tags, passingOnly, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), nodes, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checksWatch is used to watch a specific checks in a given state
|
||||||
|
func checksWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
stale := false
|
||||||
|
if err := assignValueBool(params, "stale", &stale); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var service, state string
|
||||||
|
if err := assignValue(params, "service", &service); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := assignValue(params, "state", &state); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if service != "" && state != "" {
|
||||||
|
return nil, fmt.Errorf("Cannot specify service and state")
|
||||||
|
}
|
||||||
|
if service == "" && state == "" {
|
||||||
|
state = "any"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
health := p.client.Health()
|
||||||
|
opts := makeQueryOptionsWithContext(p, stale)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
var checks []*consulapi.HealthCheck
|
||||||
|
var meta *consulapi.QueryMeta
|
||||||
|
var err error
|
||||||
|
if state != "" {
|
||||||
|
checks, meta, err = health.State(state, &opts)
|
||||||
|
} else {
|
||||||
|
checks, meta, err = health.Checks(service, &opts)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), checks, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventWatch is used to watch for events, optionally filtering on name
|
||||||
|
func eventWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
// The stale setting doesn't apply to events.
|
||||||
|
|
||||||
|
var name string
|
||||||
|
if err := assignValue(params, "name", &name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
event := p.client.Event()
|
||||||
|
opts := makeQueryOptionsWithContext(p, false)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
events, meta, err := event.List(name, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune to only the new events
|
||||||
|
for i := 0; i < len(events); i++ {
|
||||||
|
if WaitIndexVal(event.IDToIndex(events[i].ID)).Equal(p.lastParamVal) {
|
||||||
|
events = events[i+1:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WaitIndexVal(meta.LastIndex), events, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// connectRootsWatch is used to watch for changes to Connect Root certificates.
|
||||||
|
func connectRootsWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
// We don't support stale since roots are cached locally in the agent.
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
agent := p.client.Agent()
|
||||||
|
opts := makeQueryOptionsWithContext(p, false)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
|
||||||
|
roots, meta, err := agent.ConnectCARoots(&opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return WaitIndexVal(meta.LastIndex), roots, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// connectLeafWatch is used to watch for changes to Connect Leaf certificates
|
||||||
|
// for given local service id.
|
||||||
|
func connectLeafWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
// We don't support stale since certs are cached locally in the agent.
|
||||||
|
|
||||||
|
var serviceName string
|
||||||
|
if err := assignValue(params, "service", &serviceName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
agent := p.client.Agent()
|
||||||
|
opts := makeQueryOptionsWithContext(p, false)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
|
||||||
|
leaf, meta, err := agent.ConnectCALeaf(serviceName, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return WaitIndexVal(meta.LastIndex), leaf, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// agentServiceWatch is used to watch for changes to a single service instance
|
||||||
|
// on the local agent. Note that this state is agent-local so the watch
|
||||||
|
// mechanism uses `hash` rather than `index` for deciding whether to block.
|
||||||
|
func agentServiceWatch(params map[string]interface{}) (WatcherFunc, error) {
|
||||||
|
// We don't support consistency modes since it's agent local data
|
||||||
|
|
||||||
|
var serviceID string
|
||||||
|
if err := assignValue(params, "service_id", &serviceID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := func(p *Plan) (BlockingParamVal, interface{}, error) {
|
||||||
|
agent := p.client.Agent()
|
||||||
|
opts := makeQueryOptionsWithContext(p, false)
|
||||||
|
defer p.cancelFunc()
|
||||||
|
|
||||||
|
svc, _, err := agent.Service(serviceID, &opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return string ContentHash since we don't have Raft indexes to block on.
|
||||||
|
return WaitHashVal(svc.ContentHash), svc, err
|
||||||
|
}
|
||||||
|
return fn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeQueryOptionsWithContext(p *Plan, stale bool) consulapi.QueryOptions {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
p.setCancelFunc(cancel)
|
||||||
|
opts := consulapi.QueryOptions{AllowStale: stale}
|
||||||
|
switch param := p.lastParamVal.(type) {
|
||||||
|
case WaitIndexVal:
|
||||||
|
opts.WaitIndex = uint64(param)
|
||||||
|
case WaitHashVal:
|
||||||
|
opts.WaitHash = string(param)
|
||||||
|
}
|
||||||
|
return *opts.WithContext(ctx)
|
||||||
|
}
|
254
vendor/github.com/hashicorp/consul/api/watch/plan.go
generated
vendored
Normal file
254
vendor/github.com/hashicorp/consul/api/watch/plan.go
generated
vendored
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
package watch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
consulapi "github.com/hashicorp/consul/api"
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// retryInterval is the base retry value
|
||||||
|
retryInterval = 5 * time.Second
|
||||||
|
|
||||||
|
// maximum back off time, this is to prevent
|
||||||
|
// exponential runaway
|
||||||
|
maxBackoffTime = 180 * time.Second
|
||||||
|
|
||||||
|
// Name used with hclog Logger. We do not add this to the logging package
|
||||||
|
// because we do not want to pull in the root consul module.
|
||||||
|
watchLoggerName = "watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Plan) Run(address string) error {
|
||||||
|
return p.RunWithConfig(address, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run is used to run a watch plan
|
||||||
|
func (p *Plan) RunWithConfig(address string, conf *consulapi.Config) error {
|
||||||
|
logger := p.Logger
|
||||||
|
if logger == nil {
|
||||||
|
logger = newWatchLogger(p.LogOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the client
|
||||||
|
p.address = address
|
||||||
|
if conf == nil {
|
||||||
|
conf = consulapi.DefaultConfigWithLogger(logger)
|
||||||
|
}
|
||||||
|
conf.Address = address
|
||||||
|
conf.Datacenter = p.Datacenter
|
||||||
|
conf.Token = p.Token
|
||||||
|
client, err := consulapi.NewClient(conf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to connect to agent: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.RunWithClientAndHclog(client, logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunWithClientAndLogger runs a watch plan using an external client and
|
||||||
|
// hclog.Logger instance. Using this, the plan's Datacenter, Token and LogOutput
|
||||||
|
// fields are ignored and the passed client is expected to be configured as
|
||||||
|
// needed.
|
||||||
|
func (p *Plan) RunWithClientAndHclog(client *consulapi.Client, logger hclog.Logger) error {
|
||||||
|
var watchLogger hclog.Logger
|
||||||
|
if logger == nil {
|
||||||
|
watchLogger = newWatchLogger(nil)
|
||||||
|
} else {
|
||||||
|
watchLogger = logger.Named(watchLoggerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
p.client = client
|
||||||
|
|
||||||
|
// Loop until we are canceled
|
||||||
|
failures := 0
|
||||||
|
OUTER:
|
||||||
|
for !p.shouldStop() {
|
||||||
|
// Invoke the handler
|
||||||
|
blockParamVal, result, err := p.Watcher(p)
|
||||||
|
|
||||||
|
// Check if we should terminate since the function
|
||||||
|
// could have blocked for a while
|
||||||
|
if p.shouldStop() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle an error in the watch function
|
||||||
|
if err != nil {
|
||||||
|
// Perform an exponential backoff
|
||||||
|
failures++
|
||||||
|
if blockParamVal == nil {
|
||||||
|
p.lastParamVal = nil
|
||||||
|
} else {
|
||||||
|
p.lastParamVal = blockParamVal.Next(p.lastParamVal)
|
||||||
|
}
|
||||||
|
retry := retryInterval * time.Duration(failures*failures)
|
||||||
|
if retry > maxBackoffTime {
|
||||||
|
retry = maxBackoffTime
|
||||||
|
}
|
||||||
|
watchLogger.Error("Watch errored", "type", p.Type, "error", err, "retry", retry)
|
||||||
|
select {
|
||||||
|
case <-time.After(retry):
|
||||||
|
continue OUTER
|
||||||
|
case <-p.stopCh:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the failures
|
||||||
|
failures = 0
|
||||||
|
|
||||||
|
// If the index is unchanged do nothing
|
||||||
|
if p.lastParamVal != nil && p.lastParamVal.Equal(blockParamVal) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the index, look for change
|
||||||
|
oldParamVal := p.lastParamVal
|
||||||
|
p.lastParamVal = blockParamVal.Next(oldParamVal)
|
||||||
|
if oldParamVal != nil && reflect.DeepEqual(p.lastResult, result) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the updated result
|
||||||
|
p.lastResult = result
|
||||||
|
// If a hybrid handler exists use that
|
||||||
|
if p.HybridHandler != nil {
|
||||||
|
p.HybridHandler(blockParamVal, result)
|
||||||
|
} else if p.Handler != nil {
|
||||||
|
idx, ok := blockParamVal.(WaitIndexVal)
|
||||||
|
if !ok {
|
||||||
|
watchLogger.Error("Handler only supports index-based " +
|
||||||
|
" watches but non index-based watch run. Skipping Handler.")
|
||||||
|
}
|
||||||
|
p.Handler(uint64(idx), result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//Deprecated: Use RunwithClientAndHclog
|
||||||
|
func (p *Plan) RunWithClientAndLogger(client *consulapi.Client, logger *log.Logger) error {
|
||||||
|
|
||||||
|
p.client = client
|
||||||
|
|
||||||
|
// Loop until we are canceled
|
||||||
|
failures := 0
|
||||||
|
OUTER:
|
||||||
|
for !p.shouldStop() {
|
||||||
|
// Invoke the handler
|
||||||
|
blockParamVal, result, err := p.Watcher(p)
|
||||||
|
|
||||||
|
// Check if we should terminate since the function
|
||||||
|
// could have blocked for a while
|
||||||
|
if p.shouldStop() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle an error in the watch function
|
||||||
|
if err != nil {
|
||||||
|
// Perform an exponential backoff
|
||||||
|
failures++
|
||||||
|
if blockParamVal == nil {
|
||||||
|
p.lastParamVal = nil
|
||||||
|
} else {
|
||||||
|
p.lastParamVal = blockParamVal.Next(p.lastParamVal)
|
||||||
|
}
|
||||||
|
retry := retryInterval * time.Duration(failures*failures)
|
||||||
|
if retry > maxBackoffTime {
|
||||||
|
retry = maxBackoffTime
|
||||||
|
}
|
||||||
|
logger.Printf("[ERR] consul.watch: Watch (type: %s) errored: %v, retry in %v",
|
||||||
|
p.Type, err, retry)
|
||||||
|
select {
|
||||||
|
case <-time.After(retry):
|
||||||
|
continue OUTER
|
||||||
|
case <-p.stopCh:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the failures
|
||||||
|
failures = 0
|
||||||
|
|
||||||
|
// If the index is unchanged do nothing
|
||||||
|
if p.lastParamVal != nil && p.lastParamVal.Equal(blockParamVal) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the index, look for change
|
||||||
|
oldParamVal := p.lastParamVal
|
||||||
|
p.lastParamVal = blockParamVal.Next(oldParamVal)
|
||||||
|
if oldParamVal != nil && reflect.DeepEqual(p.lastResult, result) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the updated result
|
||||||
|
p.lastResult = result
|
||||||
|
// If a hybrid handler exists use that
|
||||||
|
if p.HybridHandler != nil {
|
||||||
|
p.HybridHandler(blockParamVal, result)
|
||||||
|
} else if p.Handler != nil {
|
||||||
|
idx, ok := blockParamVal.(WaitIndexVal)
|
||||||
|
if !ok {
|
||||||
|
logger.Printf("[ERR] consul.watch: Handler only supports index-based " +
|
||||||
|
" watches but non index-based watch run. Skipping Handler.")
|
||||||
|
}
|
||||||
|
p.Handler(uint64(idx), result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop is used to stop running the watch plan
|
||||||
|
func (p *Plan) Stop() {
|
||||||
|
p.stopLock.Lock()
|
||||||
|
defer p.stopLock.Unlock()
|
||||||
|
if p.stop {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.stop = true
|
||||||
|
if p.cancelFunc != nil {
|
||||||
|
p.cancelFunc()
|
||||||
|
}
|
||||||
|
close(p.stopCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plan) shouldStop() bool {
|
||||||
|
select {
|
||||||
|
case <-p.stopCh:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plan) setCancelFunc(cancel context.CancelFunc) {
|
||||||
|
p.stopLock.Lock()
|
||||||
|
defer p.stopLock.Unlock()
|
||||||
|
if p.shouldStop() {
|
||||||
|
// The watch is stopped and execute the new cancel func to stop watchFactory
|
||||||
|
cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.cancelFunc = cancel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plan) IsStopped() bool {
|
||||||
|
p.stopLock.Lock()
|
||||||
|
defer p.stopLock.Unlock()
|
||||||
|
return p.stop
|
||||||
|
}
|
||||||
|
|
||||||
|
func newWatchLogger(output io.Writer) hclog.Logger {
|
||||||
|
return hclog.New(&hclog.LoggerOptions{
|
||||||
|
Name: watchLoggerName,
|
||||||
|
Output: output,
|
||||||
|
})
|
||||||
|
}
|
293
vendor/github.com/hashicorp/consul/api/watch/watch.go
generated
vendored
Normal file
293
vendor/github.com/hashicorp/consul/api/watch/watch.go
generated
vendored
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
package watch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
consulapi "github.com/hashicorp/consul/api"
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DefaultTimeout = 10 * time.Second
|
||||||
|
|
||||||
|
// Plan is the parsed version of a watch specification. A watch provides
|
||||||
|
// the details of a query, which generates a view into the Consul data store.
|
||||||
|
// This view is watched for changes and a handler is invoked to take any
|
||||||
|
// appropriate actions.
|
||||||
|
type Plan struct {
|
||||||
|
Datacenter string
|
||||||
|
Token string
|
||||||
|
Type string
|
||||||
|
HandlerType string
|
||||||
|
Exempt map[string]interface{}
|
||||||
|
|
||||||
|
Watcher WatcherFunc
|
||||||
|
// Handler is kept for backward compatibility but only supports watches based
|
||||||
|
// on index param. To support hash based watches, set HybridHandler instead.
|
||||||
|
Handler HandlerFunc
|
||||||
|
HybridHandler HybridHandlerFunc
|
||||||
|
|
||||||
|
Logger hclog.Logger
|
||||||
|
// Deprecated: use Logger
|
||||||
|
LogOutput io.Writer
|
||||||
|
|
||||||
|
address string
|
||||||
|
client *consulapi.Client
|
||||||
|
lastParamVal BlockingParamVal
|
||||||
|
lastResult interface{}
|
||||||
|
|
||||||
|
stop bool
|
||||||
|
stopCh chan struct{}
|
||||||
|
stopLock sync.Mutex
|
||||||
|
cancelFunc context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpHandlerConfig struct {
|
||||||
|
Path string `mapstructure:"path"`
|
||||||
|
Method string `mapstructure:"method"`
|
||||||
|
Timeout time.Duration `mapstructure:"-"`
|
||||||
|
TimeoutRaw string `mapstructure:"timeout"`
|
||||||
|
Header map[string][]string `mapstructure:"header"`
|
||||||
|
TLSSkipVerify bool `mapstructure:"tls_skip_verify"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockingParamVal is an interface representing the common operations needed for
|
||||||
|
// different styles of blocking. It's used to abstract the core watch plan from
|
||||||
|
// whether we are performing index-based or hash-based blocking.
|
||||||
|
type BlockingParamVal interface {
|
||||||
|
// Equal returns whether the other param value should be considered equal
|
||||||
|
// (i.e. representing no change in the watched resource). Equal must not panic
|
||||||
|
// if other is nil.
|
||||||
|
Equal(other BlockingParamVal) bool
|
||||||
|
|
||||||
|
// Next is called when deciding which value to use on the next blocking call.
|
||||||
|
// It assumes the BlockingParamVal value it is called on is the most recent one
|
||||||
|
// returned and passes the previous one which may be nil as context. This
|
||||||
|
// allows types to customize logic around ordering without assuming there is
|
||||||
|
// an order. For example WaitIndexVal can check that the index didn't go
|
||||||
|
// backwards and if it did then reset to 0. Most other cases should just
|
||||||
|
// return themselves (the most recent value) to be used in the next request.
|
||||||
|
Next(previous BlockingParamVal) BlockingParamVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitIndexVal is a type representing a Consul index that implements
|
||||||
|
// BlockingParamVal.
|
||||||
|
type WaitIndexVal uint64
|
||||||
|
|
||||||
|
// Equal implements BlockingParamVal
|
||||||
|
func (idx WaitIndexVal) Equal(other BlockingParamVal) bool {
|
||||||
|
if otherIdx, ok := other.(WaitIndexVal); ok {
|
||||||
|
return idx == otherIdx
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next implements BlockingParamVal
|
||||||
|
func (idx WaitIndexVal) Next(previous BlockingParamVal) BlockingParamVal {
|
||||||
|
if previous == nil {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
prevIdx, ok := previous.(WaitIndexVal)
|
||||||
|
if ok && prevIdx == idx {
|
||||||
|
// This value is the same as the previous index, reset
|
||||||
|
return WaitIndexVal(0)
|
||||||
|
}
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitHashVal is a type representing a Consul content hash that implements
|
||||||
|
// BlockingParamVal.
|
||||||
|
type WaitHashVal string
|
||||||
|
|
||||||
|
// Equal implements BlockingParamVal
|
||||||
|
func (h WaitHashVal) Equal(other BlockingParamVal) bool {
|
||||||
|
if otherHash, ok := other.(WaitHashVal); ok {
|
||||||
|
return h == otherHash
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next implements BlockingParamVal
|
||||||
|
func (h WaitHashVal) Next(previous BlockingParamVal) BlockingParamVal {
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatcherFunc is used to watch for a diff.
|
||||||
|
type WatcherFunc func(*Plan) (BlockingParamVal, interface{}, error)
|
||||||
|
|
||||||
|
// HandlerFunc is used to handle new data. It only works for index-based watches
|
||||||
|
// (which is almost all end points currently) and is kept for backwards
|
||||||
|
// compatibility until more places can make use of hash-based watches too.
|
||||||
|
type HandlerFunc func(uint64, interface{})
|
||||||
|
|
||||||
|
// HybridHandlerFunc is used to handle new data. It can support either
|
||||||
|
// index-based or hash-based watches via the BlockingParamVal.
|
||||||
|
type HybridHandlerFunc func(BlockingParamVal, interface{})
|
||||||
|
|
||||||
|
// Parse takes a watch query and compiles it into a WatchPlan or an error
|
||||||
|
func Parse(params map[string]interface{}) (*Plan, error) {
|
||||||
|
return ParseExempt(params, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseExempt takes a watch query and compiles it into a WatchPlan or an error
|
||||||
|
// Any exempt parameters are stored in the Exempt map
|
||||||
|
func ParseExempt(params map[string]interface{}, exempt []string) (*Plan, error) {
|
||||||
|
plan := &Plan{
|
||||||
|
stopCh: make(chan struct{}),
|
||||||
|
Exempt: make(map[string]interface{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the generic parameters
|
||||||
|
if err := assignValue(params, "datacenter", &plan.Datacenter); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := assignValue(params, "token", &plan.Token); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := assignValue(params, "type", &plan.Type); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Ensure there is a watch type
|
||||||
|
if plan.Type == "" {
|
||||||
|
return nil, fmt.Errorf("Watch type must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the specific handler
|
||||||
|
if err := assignValue(params, "handler_type", &plan.HandlerType); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
switch plan.HandlerType {
|
||||||
|
case "http":
|
||||||
|
if _, ok := params["http_handler_config"]; !ok {
|
||||||
|
return nil, fmt.Errorf("Handler type 'http' requires 'http_handler_config' to be set")
|
||||||
|
}
|
||||||
|
config, err := parseHttpHandlerConfig(params["http_handler_config"])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(fmt.Sprintf("Failed to parse 'http_handler_config': %v", err))
|
||||||
|
}
|
||||||
|
plan.Exempt["http_handler_config"] = config
|
||||||
|
delete(params, "http_handler_config")
|
||||||
|
|
||||||
|
case "script":
|
||||||
|
// Let the caller check for configuration in exempt parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for a factory function
|
||||||
|
factory := watchFuncFactory[plan.Type]
|
||||||
|
if factory == nil {
|
||||||
|
return nil, fmt.Errorf("Unsupported watch type: %s", plan.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the watch func
|
||||||
|
fn, err := factory(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
plan.Watcher = fn
|
||||||
|
|
||||||
|
// Remove the exempt parameters
|
||||||
|
if len(exempt) > 0 {
|
||||||
|
for _, ex := range exempt {
|
||||||
|
val, ok := params[ex]
|
||||||
|
if ok {
|
||||||
|
plan.Exempt[ex] = val
|
||||||
|
delete(params, ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all parameters are consumed
|
||||||
|
if len(params) != 0 {
|
||||||
|
var bad []string
|
||||||
|
for key := range params {
|
||||||
|
bad = append(bad, key)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Invalid parameters: %v", bad)
|
||||||
|
}
|
||||||
|
return plan, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignValue is used to extract a value ensuring it is a string
|
||||||
|
func assignValue(params map[string]interface{}, name string, out *string) error {
|
||||||
|
if raw, ok := params[name]; ok {
|
||||||
|
val, ok := raw.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Expecting %s to be a string", name)
|
||||||
|
}
|
||||||
|
*out = val
|
||||||
|
delete(params, name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignValueBool is used to extract a value ensuring it is a bool
|
||||||
|
func assignValueBool(params map[string]interface{}, name string, out *bool) error {
|
||||||
|
if raw, ok := params[name]; ok {
|
||||||
|
val, ok := raw.(bool)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Expecting %s to be a boolean", name)
|
||||||
|
}
|
||||||
|
*out = val
|
||||||
|
delete(params, name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignValueStringSlice is used to extract a value ensuring it is either a string or a slice of strings
|
||||||
|
func assignValueStringSlice(params map[string]interface{}, name string, out *[]string) error {
|
||||||
|
if raw, ok := params[name]; ok {
|
||||||
|
var tmp []string
|
||||||
|
switch raw.(type) {
|
||||||
|
case string:
|
||||||
|
tmp = make([]string, 1, 1)
|
||||||
|
tmp[0] = raw.(string)
|
||||||
|
case []string:
|
||||||
|
l := len(raw.([]string))
|
||||||
|
tmp = make([]string, l, l)
|
||||||
|
copy(tmp, raw.([]string))
|
||||||
|
case []interface{}:
|
||||||
|
l := len(raw.([]interface{}))
|
||||||
|
tmp = make([]string, l, l)
|
||||||
|
for i, v := range raw.([]interface{}) {
|
||||||
|
if s, ok := v.(string); ok {
|
||||||
|
tmp[i] = s
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("Index %d of %s expected to be string", i, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Expecting %s to be a string or []string", name)
|
||||||
|
}
|
||||||
|
*out = tmp
|
||||||
|
delete(params, name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the 'http_handler_config' parameters
|
||||||
|
func parseHttpHandlerConfig(configParams interface{}) (*HttpHandlerConfig, error) {
|
||||||
|
var config HttpHandlerConfig
|
||||||
|
if err := mapstructure.Decode(configParams, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Path == "" {
|
||||||
|
return nil, fmt.Errorf("Requires 'path' to be set")
|
||||||
|
}
|
||||||
|
if config.Method == "" {
|
||||||
|
config.Method = "POST"
|
||||||
|
}
|
||||||
|
if config.TimeoutRaw == "" {
|
||||||
|
config.Timeout = DefaultTimeout
|
||||||
|
} else if timeout, err := time.ParseDuration(config.TimeoutRaw); err != nil {
|
||||||
|
return nil, fmt.Errorf(fmt.Sprintf("Failed to parse timeout: %v", err))
|
||||||
|
} else {
|
||||||
|
config.Timeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config, nil
|
||||||
|
}
|
37
vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_darwin.go
generated
vendored
Normal file
37
vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_darwin.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//+build darwin
|
||||||
|
|
||||||
|
package freeport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ephemeralPortRangeSysctlFirst = "net.inet.ip.portrange.first"
|
||||||
|
const ephemeralPortRangeSysctlLast = "net.inet.ip.portrange.last"
|
||||||
|
|
||||||
|
var ephemeralPortRangePatt = regexp.MustCompile(`^\s*(\d+)\s+(\d+)\s*$`)
|
||||||
|
|
||||||
|
func getEphemeralPortRange() (int, int, error) {
|
||||||
|
cmd := exec.Command("/usr/sbin/sysctl", "-n", ephemeralPortRangeSysctlFirst, ephemeralPortRangeSysctlLast)
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
val := string(out)
|
||||||
|
|
||||||
|
m := ephemeralPortRangePatt.FindStringSubmatch(val)
|
||||||
|
if m != nil {
|
||||||
|
min, err1 := strconv.Atoi(m[1])
|
||||||
|
max, err2 := strconv.Atoi(m[2])
|
||||||
|
|
||||||
|
if err1 == nil && err2 == nil {
|
||||||
|
return min, max, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, 0, fmt.Errorf("unexpected sysctl value %q for keys %q, %q", val, ephemeralPortRangeSysctlFirst, ephemeralPortRangeSysctlLast)
|
||||||
|
}
|
7
vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_fallback.go
generated
vendored
Normal file
7
vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_fallback.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//+build !linux,!darwin
|
||||||
|
|
||||||
|
package freeport
|
||||||
|
|
||||||
|
func getEphemeralPortRange() (int, int, error) {
|
||||||
|
return 0, 0, nil
|
||||||
|
}
|
36
vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_linux.go
generated
vendored
Normal file
36
vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_linux.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//+build linux
|
||||||
|
|
||||||
|
package freeport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ephemeralPortRangeSysctlKey = "net.ipv4.ip_local_port_range"
|
||||||
|
|
||||||
|
var ephemeralPortRangePatt = regexp.MustCompile(`^\s*(\d+)\s+(\d+)\s*$`)
|
||||||
|
|
||||||
|
func getEphemeralPortRange() (int, int, error) {
|
||||||
|
cmd := exec.Command("/sbin/sysctl", "-n", ephemeralPortRangeSysctlKey)
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
val := string(out)
|
||||||
|
|
||||||
|
m := ephemeralPortRangePatt.FindStringSubmatch(val)
|
||||||
|
if m != nil {
|
||||||
|
min, err1 := strconv.Atoi(m[1])
|
||||||
|
max, err2 := strconv.Atoi(m[2])
|
||||||
|
|
||||||
|
if err1 == nil && err2 == nil {
|
||||||
|
return min, max, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, 0, fmt.Errorf("unexpected sysctl value %q for key %q", val, ephemeralPortRangeSysctlKey)
|
||||||
|
}
|
391
vendor/github.com/hashicorp/consul/sdk/freeport/freeport.go
generated
vendored
Normal file
391
vendor/github.com/hashicorp/consul/sdk/freeport/freeport.go
generated
vendored
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
// Package freeport provides a helper for allocating free ports across multiple
|
||||||
|
// processes on the same machine.
|
||||||
|
package freeport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-testing-interface"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// maxBlocks is the number of available port blocks before exclusions.
|
||||||
|
maxBlocks = 30
|
||||||
|
|
||||||
|
// lowPort is the lowest port number that should be used.
|
||||||
|
lowPort = 10000
|
||||||
|
|
||||||
|
// attempts is how often we try to allocate a port block
|
||||||
|
// before giving up.
|
||||||
|
attempts = 10
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// blockSize is the size of the allocated port block. ports are given out
|
||||||
|
// consecutively from that block and after that point in a LRU fashion.
|
||||||
|
blockSize int
|
||||||
|
|
||||||
|
// effectiveMaxBlocks is the number of available port blocks.
|
||||||
|
// lowPort + effectiveMaxBlocks * blockSize must be less than 65535.
|
||||||
|
effectiveMaxBlocks int
|
||||||
|
|
||||||
|
// firstPort is the first port of the allocated block.
|
||||||
|
firstPort int
|
||||||
|
|
||||||
|
// lockLn is the system-wide mutex for the port block.
|
||||||
|
lockLn net.Listener
|
||||||
|
|
||||||
|
// mu guards:
|
||||||
|
// - pendingPorts
|
||||||
|
// - freePorts
|
||||||
|
// - total
|
||||||
|
mu sync.Mutex
|
||||||
|
|
||||||
|
// once is used to do the initialization on the first call to retrieve free
|
||||||
|
// ports
|
||||||
|
once sync.Once
|
||||||
|
|
||||||
|
// condNotEmpty is a condition variable to wait for freePorts to be not
|
||||||
|
// empty. Linked to 'mu'
|
||||||
|
condNotEmpty *sync.Cond
|
||||||
|
|
||||||
|
// freePorts is a FIFO of all currently free ports. Take from the front,
|
||||||
|
// and return to the back.
|
||||||
|
freePorts *list.List
|
||||||
|
|
||||||
|
// pendingPorts is a FIFO of recently freed ports that have not yet passed
|
||||||
|
// the not-in-use check.
|
||||||
|
pendingPorts *list.List
|
||||||
|
|
||||||
|
// total is the total number of available ports in the block for use.
|
||||||
|
total int
|
||||||
|
|
||||||
|
// stopCh is used to signal to background goroutines to terminate. Only
|
||||||
|
// really exists for the safety of reset() during unit tests.
|
||||||
|
stopCh chan struct{}
|
||||||
|
|
||||||
|
// stopWg is used to keep track of background goroutines that are still
|
||||||
|
// alive. Only really exists for the safety of reset() during unit tests.
|
||||||
|
stopWg sync.WaitGroup
|
||||||
|
)
|
||||||
|
|
||||||
|
// initialize is used to initialize freeport.
|
||||||
|
func initialize() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
blockSize = 1500
|
||||||
|
limit, err := systemLimit()
|
||||||
|
if err != nil {
|
||||||
|
panic("freeport: error getting system limit: " + err.Error())
|
||||||
|
}
|
||||||
|
if limit > 0 && limit < blockSize {
|
||||||
|
logf("INFO", "blockSize %d too big for system limit %d. Adjusting...", blockSize, limit)
|
||||||
|
blockSize = limit - 3
|
||||||
|
}
|
||||||
|
|
||||||
|
effectiveMaxBlocks, err = adjustMaxBlocks()
|
||||||
|
if err != nil {
|
||||||
|
panic("freeport: ephemeral port range detection failed: " + err.Error())
|
||||||
|
}
|
||||||
|
if effectiveMaxBlocks < 0 {
|
||||||
|
panic("freeport: no blocks of ports available outside of ephemeral range")
|
||||||
|
}
|
||||||
|
if lowPort+effectiveMaxBlocks*blockSize > 65535 {
|
||||||
|
panic("freeport: block size too big or too many blocks requested")
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
firstPort, lockLn = alloc()
|
||||||
|
|
||||||
|
condNotEmpty = sync.NewCond(&mu)
|
||||||
|
freePorts = list.New()
|
||||||
|
pendingPorts = list.New()
|
||||||
|
|
||||||
|
// fill with all available free ports
|
||||||
|
for port := firstPort + 1; port < firstPort+blockSize; port++ {
|
||||||
|
if used := isPortInUse(port); !used {
|
||||||
|
freePorts.PushBack(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total = freePorts.Len()
|
||||||
|
|
||||||
|
stopWg.Add(1)
|
||||||
|
stopCh = make(chan struct{})
|
||||||
|
// Note: we pass this param explicitly to the goroutine so that we can
|
||||||
|
// freely recreate the underlying stop channel during reset() after closing
|
||||||
|
// the original.
|
||||||
|
go checkFreedPorts(stopCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
func shutdownGoroutine() {
|
||||||
|
mu.Lock()
|
||||||
|
if stopCh == nil {
|
||||||
|
mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
close(stopCh)
|
||||||
|
stopCh = nil
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
stopWg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset will reverse the setup from initialize() and then redo it (for tests)
|
||||||
|
func reset() {
|
||||||
|
logf("INFO", "resetting the freeport package state")
|
||||||
|
shutdownGoroutine()
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
effectiveMaxBlocks = 0
|
||||||
|
firstPort = 0
|
||||||
|
if lockLn != nil {
|
||||||
|
lockLn.Close()
|
||||||
|
lockLn = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
once = sync.Once{}
|
||||||
|
|
||||||
|
freePorts = nil
|
||||||
|
pendingPorts = nil
|
||||||
|
total = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFreedPorts(stopCh <-chan struct{}) {
|
||||||
|
defer stopWg.Done()
|
||||||
|
|
||||||
|
ticker := time.NewTicker(250 * time.Millisecond)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-stopCh:
|
||||||
|
logf("INFO", "Closing checkFreedPorts()")
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
checkFreedPortsOnce()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFreedPortsOnce() {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
pending := pendingPorts.Len()
|
||||||
|
remove := make([]*list.Element, 0, pending)
|
||||||
|
for elem := pendingPorts.Front(); elem != nil; elem = elem.Next() {
|
||||||
|
port := elem.Value.(int)
|
||||||
|
if used := isPortInUse(port); !used {
|
||||||
|
freePorts.PushBack(port)
|
||||||
|
remove = append(remove, elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
retained := pending - len(remove)
|
||||||
|
|
||||||
|
if retained > 0 {
|
||||||
|
logf("WARN", "%d out of %d pending ports are still in use; something probably didn't wait around for the port to be closed!", retained, pending)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remove) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, elem := range remove {
|
||||||
|
pendingPorts.Remove(elem)
|
||||||
|
}
|
||||||
|
|
||||||
|
condNotEmpty.Broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjustMaxBlocks avoids having the allocation ranges overlap the ephemeral
|
||||||
|
// port range.
|
||||||
|
func adjustMaxBlocks() (int, error) {
|
||||||
|
ephemeralPortMin, ephemeralPortMax, err := getEphemeralPortRange()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if ephemeralPortMin <= 0 || ephemeralPortMax <= 0 {
|
||||||
|
logf("INFO", "ephemeral port range detection not configured for GOOS=%q", runtime.GOOS)
|
||||||
|
return maxBlocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logf("INFO", "detected ephemeral port range of [%d, %d]", ephemeralPortMin, ephemeralPortMax)
|
||||||
|
for block := 0; block < maxBlocks; block++ {
|
||||||
|
min := lowPort + block*blockSize
|
||||||
|
max := min + blockSize
|
||||||
|
overlap := intervalOverlap(min, max-1, ephemeralPortMin, ephemeralPortMax)
|
||||||
|
if overlap {
|
||||||
|
logf("INFO", "reducing max blocks from %d to %d to avoid the ephemeral port range", maxBlocks, block)
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxBlocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// alloc reserves a port block for exclusive use for the lifetime of the
|
||||||
|
// application. lockLn serves as a system-wide mutex for the port block and is
|
||||||
|
// implemented as a TCP listener which is bound to the firstPort and which will
|
||||||
|
// be automatically released when the application terminates.
|
||||||
|
func alloc() (int, net.Listener) {
|
||||||
|
for i := 0; i < attempts; i++ {
|
||||||
|
block := int(rand.Int31n(int32(effectiveMaxBlocks)))
|
||||||
|
firstPort := lowPort + block*blockSize
|
||||||
|
ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", firstPort))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// logf("DEBUG", "allocated port block %d (%d-%d)", block, firstPort, firstPort+blockSize-1)
|
||||||
|
return firstPort, ln
|
||||||
|
}
|
||||||
|
panic("freeport: cannot allocate port block")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustTake is the same as Take except it panics on error.
|
||||||
|
func MustTake(n int) (ports []int) {
|
||||||
|
ports, err := Take(n)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return ports
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take returns a list of free ports from the allocated port block. It is safe
|
||||||
|
// to call this method concurrently. Ports have been tested to be available on
|
||||||
|
// 127.0.0.1 TCP but there is no guarantee that they will remain free in the
|
||||||
|
// future.
|
||||||
|
func Take(n int) (ports []int, err error) {
|
||||||
|
if n <= 0 {
|
||||||
|
return nil, fmt.Errorf("freeport: cannot take %d ports", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
// Reserve a port block
|
||||||
|
once.Do(initialize)
|
||||||
|
|
||||||
|
if n > total {
|
||||||
|
return nil, fmt.Errorf("freeport: block size too small")
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(ports) < n {
|
||||||
|
for freePorts.Len() == 0 {
|
||||||
|
if total == 0 {
|
||||||
|
return nil, fmt.Errorf("freeport: impossible to satisfy request; there are no actual free ports in the block anymore")
|
||||||
|
}
|
||||||
|
condNotEmpty.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
elem := freePorts.Front()
|
||||||
|
freePorts.Remove(elem)
|
||||||
|
port := elem.Value.(int)
|
||||||
|
|
||||||
|
if used := isPortInUse(port); used {
|
||||||
|
// Something outside of the test suite has stolen this port, possibly
|
||||||
|
// due to assignment to an ephemeral port, remove it completely.
|
||||||
|
logf("WARN", "leaked port %d due to theft; removing from circulation", port)
|
||||||
|
total--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ports = append(ports, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// logf("DEBUG", "free ports: %v", ports)
|
||||||
|
return ports, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// peekFree returns the next port that will be returned by Take to aid in testing.
|
||||||
|
func peekFree() int {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
return freePorts.Front().Value.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// peekAllFree returns all free ports that could be returned by Take to aid in testing.
|
||||||
|
func peekAllFree() []int {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
var out []int
|
||||||
|
for elem := freePorts.Front(); elem != nil; elem = elem.Next() {
|
||||||
|
port := elem.Value.(int)
|
||||||
|
out = append(out, port)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// stats returns diagnostic data to aid in testing
|
||||||
|
func stats() (numTotal, numPending, numFree int) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
return total, pendingPorts.Len(), freePorts.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return returns a block of ports back to the general pool. These ports should
|
||||||
|
// have been returned from a call to Take().
|
||||||
|
func Return(ports []int) {
|
||||||
|
if len(ports) == 0 {
|
||||||
|
return // convenience short circuit for test ergonomics
|
||||||
|
}
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
for _, port := range ports {
|
||||||
|
if port > firstPort && port < firstPort+blockSize {
|
||||||
|
pendingPorts.PushBack(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPortInUse(port int) bool {
|
||||||
|
ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", port))
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ln.Close()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcpAddr(ip string, port int) *net.TCPAddr {
|
||||||
|
return &net.TCPAddr{IP: net.ParseIP(ip), Port: port}
|
||||||
|
}
|
||||||
|
|
||||||
|
// intervalOverlap returns true if the doubly-inclusive integer intervals
|
||||||
|
// represented by [min1, max1] and [min2, max2] overlap.
|
||||||
|
func intervalOverlap(min1, max1, min2, max2 int) bool {
|
||||||
|
if min1 > max1 {
|
||||||
|
logf("WARN", "interval1 is not ordered [%d, %d]", min1, max1)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if min2 > max2 {
|
||||||
|
logf("WARN", "interval2 is not ordered [%d, %d]", min2, max2)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return min1 <= max2 && min2 <= max1
|
||||||
|
}
|
||||||
|
|
||||||
|
func logf(severity string, format string, a ...interface{}) {
|
||||||
|
fmt.Fprintf(os.Stderr, "["+severity+"] freeport: "+format+"\n", a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Please use Take/Return calls instead.
|
||||||
|
func Get(n int) (ports []int) { return MustTake(n) }
|
||||||
|
|
||||||
|
// Deprecated: Please use Take/Return calls instead.
|
||||||
|
func GetT(t testing.T, n int) (ports []int) { return MustTake(n) }
|
||||||
|
|
||||||
|
// Deprecated: Please use Take/Return calls instead.
|
||||||
|
func Free(n int) (ports []int, err error) { return MustTake(n), nil }
|
11
vendor/github.com/hashicorp/consul/sdk/freeport/systemlimit.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/consul/sdk/freeport/systemlimit.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package freeport
|
||||||
|
|
||||||
|
import "golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
func systemLimit() (int, error) {
|
||||||
|
var limit unix.Rlimit
|
||||||
|
err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit)
|
||||||
|
return int(limit.Cur), err
|
||||||
|
}
|
7
vendor/github.com/hashicorp/consul/sdk/freeport/systemlimit_windows.go
generated
vendored
Normal file
7
vendor/github.com/hashicorp/consul/sdk/freeport/systemlimit_windows.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package freeport
|
||||||
|
|
||||||
|
func systemLimit() (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
78
vendor/github.com/hashicorp/consul/sdk/testutil/README.md
generated
vendored
Normal file
78
vendor/github.com/hashicorp/consul/sdk/testutil/README.md
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
Consul Testing Utilities
|
||||||
|
========================
|
||||||
|
|
||||||
|
This package provides some generic helpers to facilitate testing in Consul.
|
||||||
|
|
||||||
|
TestServer
|
||||||
|
==========
|
||||||
|
|
||||||
|
TestServer is a harness for managing Consul agents and initializing them with
|
||||||
|
test data. Using it, you can form test clusters, create services, add health
|
||||||
|
checks, manipulate the K/V store, etc. This test harness is completely decoupled
|
||||||
|
from Consul's core and API client, meaning it can be easily imported and used in
|
||||||
|
external unit tests for various applications. It works by invoking the Consul
|
||||||
|
CLI, which means it is a requirement to have Consul installed in the `$PATH`.
|
||||||
|
|
||||||
|
Following is an example usage:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package my_program
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/consul/structs"
|
||||||
|
"github.com/hashicorp/consul/sdk/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFoo_bar(t *testing.T) {
|
||||||
|
// Create a test Consul server
|
||||||
|
srv1, err := testutil.NewTestServerConfigT(t, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer srv1.Stop()
|
||||||
|
|
||||||
|
// Create a secondary server, passing in configuration
|
||||||
|
// to avoid bootstrapping as we are forming a cluster.
|
||||||
|
srv2, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) {
|
||||||
|
c.Bootstrap = false
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer srv2.Stop()
|
||||||
|
|
||||||
|
// Join the servers together
|
||||||
|
srv1.JoinLAN(t, srv2.LANAddr)
|
||||||
|
|
||||||
|
// Create a test key/value pair
|
||||||
|
srv1.SetKV(t, "foo", []byte("bar"))
|
||||||
|
|
||||||
|
// Create lots of test key/value pairs
|
||||||
|
srv1.PopulateKV(t, map[string][]byte{
|
||||||
|
"bar": []byte("123"),
|
||||||
|
"baz": []byte("456"),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a service
|
||||||
|
srv1.AddService(t, "redis", structs.HealthPassing, []string{"master"})
|
||||||
|
|
||||||
|
// Create a service that will be accessed in target source code
|
||||||
|
srv1.AddAccessibleService("redis", structs.HealthPassing, "127.0.0.1", 6379, []string{"master"})
|
||||||
|
|
||||||
|
// Create a service check
|
||||||
|
srv1.AddCheck(t, "service:redis", "redis", structs.HealthPassing)
|
||||||
|
|
||||||
|
// Create a node check
|
||||||
|
srv1.AddCheck(t, "mem", "", structs.HealthCritical)
|
||||||
|
|
||||||
|
// The HTTPAddr field contains the address of the Consul
|
||||||
|
// API on the new test server instance.
|
||||||
|
println(srv1.HTTPAddr)
|
||||||
|
|
||||||
|
// All functions also have a wrapper method to limit the passing of "t"
|
||||||
|
wrap := srv1.Wrap(t)
|
||||||
|
wrap.SetKV("foo", []byte("bar"))
|
||||||
|
}
|
||||||
|
```
|
19
vendor/github.com/hashicorp/consul/sdk/testutil/assertions.go
generated
vendored
Normal file
19
vendor/github.com/hashicorp/consul/sdk/testutil/assertions.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequireErrorContains is a test helper for asserting that an error occurred
|
||||||
|
// and the error message returned contains the expected error message as a
|
||||||
|
// substring.
|
||||||
|
func RequireErrorContains(t *testing.T, err error, expectedErrorMessage string) {
|
||||||
|
t.Helper()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("An error is expected but got nil.")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), expectedErrorMessage) {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
82
vendor/github.com/hashicorp/consul/sdk/testutil/io.go
generated
vendored
Normal file
82
vendor/github.com/hashicorp/consul/sdk/testutil/io.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// tmpdir is the base directory for all temporary directories
|
||||||
|
// and files created with TempDir and TempFile. This could be
|
||||||
|
// achieved by setting a system environment variable but then
|
||||||
|
// the test execution would depend on whether or not the
|
||||||
|
// environment variable is set.
|
||||||
|
//
|
||||||
|
// On macOS the temp base directory is quite long and that
|
||||||
|
// triggers a problem with some tests that bind to UNIX sockets
|
||||||
|
// where the filename seems to be too long. Using a shorter name
|
||||||
|
// fixes this and makes the paths more readable.
|
||||||
|
//
|
||||||
|
// It also provides a single base directory for cleanup.
|
||||||
|
var tmpdir = "/tmp/consul-test"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if err := os.MkdirAll(tmpdir, 0755); err != nil {
|
||||||
|
fmt.Printf("Cannot create %s. Reverting to /tmp\n", tmpdir)
|
||||||
|
tmpdir = "/tmp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var noCleanup = strings.ToLower(os.Getenv("TEST_NOCLEANUP")) == "true"
|
||||||
|
|
||||||
|
// TempDir creates a temporary directory within tmpdir with the name 'testname-name'.
|
||||||
|
// If the directory cannot be created t.Fatal is called.
|
||||||
|
// The directory will be removed when the test ends. Set TEST_NOCLEANUP env var
|
||||||
|
// to prevent the directory from being removed.
|
||||||
|
func TempDir(t *testing.T, name string) string {
|
||||||
|
if t == nil {
|
||||||
|
panic("argument t must be non-nil")
|
||||||
|
}
|
||||||
|
name = t.Name() + "-" + name
|
||||||
|
name = strings.Replace(name, "/", "_", -1)
|
||||||
|
d, err := ioutil.TempDir(tmpdir, name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if noCleanup {
|
||||||
|
t.Logf("skipping cleanup because TEST_NOCLEANUP was enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.RemoveAll(d)
|
||||||
|
})
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// TempFile creates a temporary file within tmpdir with the name 'testname-name'.
|
||||||
|
// If the file cannot be created t.Fatal is called. If a temporary directory
|
||||||
|
// has been created before consider storing the file inside this directory to
|
||||||
|
// avoid double cleanup.
|
||||||
|
// The file will be removed when the test ends. Set TEST_NOCLEANUP env var
|
||||||
|
// to prevent the file from being removed.
|
||||||
|
func TempFile(t *testing.T, name string) *os.File {
|
||||||
|
if t == nil {
|
||||||
|
panic("argument t must be non-nil")
|
||||||
|
}
|
||||||
|
name = t.Name() + "-" + name
|
||||||
|
name = strings.Replace(name, "/", "_", -1)
|
||||||
|
f, err := ioutil.TempFile(tmpdir, name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if noCleanup {
|
||||||
|
t.Logf("skipping cleanup because TEST_NOCLEANUP was enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Remove(f.Name())
|
||||||
|
})
|
||||||
|
return f
|
||||||
|
}
|
210
vendor/github.com/hashicorp/consul/sdk/testutil/retry/retry.go
generated
vendored
Normal file
210
vendor/github.com/hashicorp/consul/sdk/testutil/retry/retry.go
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
// Package retry provides support for repeating operations in tests.
|
||||||
|
//
|
||||||
|
// A sample retry operation looks like this:
|
||||||
|
//
|
||||||
|
// func TestX(t *testing.T) {
|
||||||
|
// retry.Run(t, func(r *retry.R) {
|
||||||
|
// if err := foo(); err != nil {
|
||||||
|
// r.Fatal("f: ", err)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
package retry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Failer is an interface compatible with testing.T.
|
||||||
|
type Failer interface {
|
||||||
|
Helper()
|
||||||
|
|
||||||
|
// Log is called for the final test output
|
||||||
|
Log(args ...interface{})
|
||||||
|
|
||||||
|
// FailNow is called when the retrying is abandoned.
|
||||||
|
FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// R provides context for the retryer.
|
||||||
|
type R struct {
|
||||||
|
fail bool
|
||||||
|
output []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) FailNow() {
|
||||||
|
r.fail = true
|
||||||
|
runtime.Goexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) Fatal(args ...interface{}) {
|
||||||
|
r.log(fmt.Sprint(args...))
|
||||||
|
r.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) Fatalf(format string, args ...interface{}) {
|
||||||
|
r.log(fmt.Sprintf(format, args...))
|
||||||
|
r.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) Error(args ...interface{}) {
|
||||||
|
r.log(fmt.Sprint(args...))
|
||||||
|
r.fail = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) Errorf(format string, args ...interface{}) {
|
||||||
|
r.log(fmt.Sprintf(format, args...))
|
||||||
|
r.fail = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) Check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
r.log(err.Error())
|
||||||
|
r.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *R) log(s string) {
|
||||||
|
r.output = append(r.output, decorate(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func decorate(s string) string {
|
||||||
|
_, file, line, ok := runtime.Caller(3)
|
||||||
|
if ok {
|
||||||
|
n := strings.LastIndex(file, "/")
|
||||||
|
if n >= 0 {
|
||||||
|
file = file[n+1:]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file = "???"
|
||||||
|
line = 1
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s:%d: %s", file, line, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run(t Failer, f func(r *R)) {
|
||||||
|
run(DefaultFailer(), t, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunWith(r Retryer, t Failer, f func(r *R)) {
|
||||||
|
run(r, t, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dedup(a []string) string {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
m := map[string]int{}
|
||||||
|
for _, s := range a {
|
||||||
|
m[s] = m[s] + 1
|
||||||
|
}
|
||||||
|
var b bytes.Buffer
|
||||||
|
for _, s := range a {
|
||||||
|
if _, ok := m[s]; ok {
|
||||||
|
b.WriteString(s)
|
||||||
|
b.WriteRune('\n')
|
||||||
|
delete(m, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(r Retryer, t Failer, f func(r *R)) {
|
||||||
|
rr := &R{}
|
||||||
|
fail := func() {
|
||||||
|
t.Helper()
|
||||||
|
out := dedup(rr.output)
|
||||||
|
if out != "" {
|
||||||
|
t.Log(out)
|
||||||
|
}
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
for r.NextOr(fail) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
f(rr)
|
||||||
|
}()
|
||||||
|
wg.Wait()
|
||||||
|
if rr.fail {
|
||||||
|
rr.fail = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultFailer provides default retry.Run() behavior for unit tests.
|
||||||
|
func DefaultFailer() *Timer {
|
||||||
|
return &Timer{Timeout: 7 * time.Second, Wait: 25 * time.Millisecond}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TwoSeconds repeats an operation for two seconds and waits 25ms in between.
|
||||||
|
func TwoSeconds() *Timer {
|
||||||
|
return &Timer{Timeout: 2 * time.Second, Wait: 25 * time.Millisecond}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThreeTimes repeats an operation three times and waits 25ms in between.
|
||||||
|
func ThreeTimes() *Counter {
|
||||||
|
return &Counter{Count: 3, Wait: 25 * time.Millisecond}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retryer provides an interface for repeating operations
|
||||||
|
// until they succeed or an exit condition is met.
|
||||||
|
type Retryer interface {
|
||||||
|
// NextOr returns true if the operation should be repeated.
|
||||||
|
// Otherwise, it calls fail and returns false.
|
||||||
|
NextOr(fail func()) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counter repeats an operation a given number of
|
||||||
|
// times and waits between subsequent operations.
|
||||||
|
type Counter struct {
|
||||||
|
Count int
|
||||||
|
Wait time.Duration
|
||||||
|
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Counter) NextOr(fail func()) bool {
|
||||||
|
if r.count == r.Count {
|
||||||
|
fail()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if r.count > 0 {
|
||||||
|
time.Sleep(r.Wait)
|
||||||
|
}
|
||||||
|
r.count++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer repeats an operation for a given amount
|
||||||
|
// of time and waits between subsequent operations.
|
||||||
|
type Timer struct {
|
||||||
|
Timeout time.Duration
|
||||||
|
Wait time.Duration
|
||||||
|
|
||||||
|
// stop is the timeout deadline.
|
||||||
|
// Set on the first invocation of Next().
|
||||||
|
stop time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Timer) NextOr(fail func()) bool {
|
||||||
|
if r.stop.IsZero() {
|
||||||
|
r.stop = time.Now().Add(r.Timeout)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if time.Now().After(r.stop) {
|
||||||
|
fail()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
time.Sleep(r.Wait)
|
||||||
|
return true
|
||||||
|
}
|
514
vendor/github.com/hashicorp/consul/sdk/testutil/server.go
generated
vendored
Normal file
514
vendor/github.com/hashicorp/consul/sdk/testutil/server.go
generated
vendored
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
// TestServer is a test helper. It uses a fork/exec model to create
|
||||||
|
// a test Consul server instance in the background and initialize it
|
||||||
|
// with some data and/or services. The test server can then be used
|
||||||
|
// to run a unit test, and offers an easy API to tear itself down
|
||||||
|
// when the test has completed. The only prerequisite is to have a consul
|
||||||
|
// binary available on the $PATH.
|
||||||
|
//
|
||||||
|
// This package does not use Consul's official API client. This is
|
||||||
|
// because we use TestServer to test the API client, which would
|
||||||
|
// otherwise cause an import cycle.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/sdk/freeport"
|
||||||
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
||||||
|
"github.com/hashicorp/go-cleanhttp"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestPerformanceConfig configures the performance parameters.
|
||||||
|
type TestPerformanceConfig struct {
|
||||||
|
RaftMultiplier uint `json:"raft_multiplier,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPortConfig configures the various ports used for services
|
||||||
|
// provided by the Consul server.
|
||||||
|
type TestPortConfig struct {
|
||||||
|
DNS int `json:"dns,omitempty"`
|
||||||
|
HTTP int `json:"http,omitempty"`
|
||||||
|
HTTPS int `json:"https,omitempty"`
|
||||||
|
SerfLan int `json:"serf_lan,omitempty"`
|
||||||
|
SerfWan int `json:"serf_wan,omitempty"`
|
||||||
|
Server int `json:"server,omitempty"`
|
||||||
|
ProxyMinPort int `json:"proxy_min_port,omitempty"`
|
||||||
|
ProxyMaxPort int `json:"proxy_max_port,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestAddressConfig contains the bind addresses for various
|
||||||
|
// components of the Consul server.
|
||||||
|
type TestAddressConfig struct {
|
||||||
|
HTTP string `json:"http,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNetworkSegment contains the configuration for a network segment.
|
||||||
|
type TestNetworkSegment struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Bind string `json:"bind"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Advertise string `json:"advertise"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestServerConfig is the main server configuration struct.
|
||||||
|
type TestServerConfig struct {
|
||||||
|
NodeName string `json:"node_name"`
|
||||||
|
NodeID string `json:"node_id"`
|
||||||
|
NodeMeta map[string]string `json:"node_meta,omitempty"`
|
||||||
|
Performance *TestPerformanceConfig `json:"performance,omitempty"`
|
||||||
|
Bootstrap bool `json:"bootstrap,omitempty"`
|
||||||
|
Server bool `json:"server,omitempty"`
|
||||||
|
DataDir string `json:"data_dir,omitempty"`
|
||||||
|
Datacenter string `json:"datacenter,omitempty"`
|
||||||
|
Segments []TestNetworkSegment `json:"segments"`
|
||||||
|
DisableCheckpoint bool `json:"disable_update_check"`
|
||||||
|
LogLevel string `json:"log_level,omitempty"`
|
||||||
|
Bind string `json:"bind_addr,omitempty"`
|
||||||
|
Addresses *TestAddressConfig `json:"addresses,omitempty"`
|
||||||
|
Ports *TestPortConfig `json:"ports,omitempty"`
|
||||||
|
RaftProtocol int `json:"raft_protocol,omitempty"`
|
||||||
|
ACLMasterToken string `json:"acl_master_token,omitempty"`
|
||||||
|
ACLDatacenter string `json:"acl_datacenter,omitempty"`
|
||||||
|
PrimaryDatacenter string `json:"primary_datacenter,omitempty"`
|
||||||
|
ACLDefaultPolicy string `json:"acl_default_policy,omitempty"`
|
||||||
|
ACL TestACLs `json:"acl,omitempty"`
|
||||||
|
Encrypt string `json:"encrypt,omitempty"`
|
||||||
|
CAFile string `json:"ca_file,omitempty"`
|
||||||
|
CertFile string `json:"cert_file,omitempty"`
|
||||||
|
KeyFile string `json:"key_file,omitempty"`
|
||||||
|
VerifyIncoming bool `json:"verify_incoming,omitempty"`
|
||||||
|
VerifyIncomingRPC bool `json:"verify_incoming_rpc,omitempty"`
|
||||||
|
VerifyIncomingHTTPS bool `json:"verify_incoming_https,omitempty"`
|
||||||
|
VerifyOutgoing bool `json:"verify_outgoing,omitempty"`
|
||||||
|
EnableScriptChecks bool `json:"enable_script_checks,omitempty"`
|
||||||
|
Connect map[string]interface{} `json:"connect,omitempty"`
|
||||||
|
EnableDebug bool `json:"enable_debug,omitempty"`
|
||||||
|
ReadyTimeout time.Duration `json:"-"`
|
||||||
|
Stdout io.Writer `json:"-"`
|
||||||
|
Stderr io.Writer `json:"-"`
|
||||||
|
Args []string `json:"-"`
|
||||||
|
ReturnPorts func() `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestACLs struct {
|
||||||
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
|
TokenReplication bool `json:"enable_token_replication,omitempty"`
|
||||||
|
PolicyTTL string `json:"policy_ttl,omitempty"`
|
||||||
|
TokenTTL string `json:"token_ttl,omitempty"`
|
||||||
|
DownPolicy string `json:"down_policy,omitempty"`
|
||||||
|
DefaultPolicy string `json:"default_policy,omitempty"`
|
||||||
|
EnableKeyListPolicy bool `json:"enable_key_list_policy,omitempty"`
|
||||||
|
Tokens TestTokens `json:"tokens,omitempty"`
|
||||||
|
DisabledTTL string `json:"disabled_ttl,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestTokens struct {
|
||||||
|
Master string `json:"master,omitempty"`
|
||||||
|
Replication string `json:"replication,omitempty"`
|
||||||
|
AgentMaster string `json:"agent_master,omitempty"`
|
||||||
|
Default string `json:"default,omitempty"`
|
||||||
|
Agent string `json:"agent,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerConfigCallback is a function interface which can be
|
||||||
|
// passed to NewTestServerConfig to modify the server config.
|
||||||
|
type ServerConfigCallback func(c *TestServerConfig)
|
||||||
|
|
||||||
|
// defaultServerConfig returns a new TestServerConfig struct
|
||||||
|
// with all of the listen ports incremented by one.
|
||||||
|
func defaultServerConfig(t CleanupT) *TestServerConfig {
|
||||||
|
nodeID, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ports := freeport.MustTake(6)
|
||||||
|
logBuffer := NewLogBuffer(t)
|
||||||
|
|
||||||
|
return &TestServerConfig{
|
||||||
|
NodeName: "node-" + nodeID,
|
||||||
|
NodeID: nodeID,
|
||||||
|
DisableCheckpoint: true,
|
||||||
|
Performance: &TestPerformanceConfig{
|
||||||
|
RaftMultiplier: 1,
|
||||||
|
},
|
||||||
|
Bootstrap: true,
|
||||||
|
Server: true,
|
||||||
|
LogLevel: "debug",
|
||||||
|
Bind: "127.0.0.1",
|
||||||
|
Addresses: &TestAddressConfig{},
|
||||||
|
Ports: &TestPortConfig{
|
||||||
|
DNS: ports[0],
|
||||||
|
HTTP: ports[1],
|
||||||
|
HTTPS: ports[2],
|
||||||
|
SerfLan: ports[3],
|
||||||
|
SerfWan: ports[4],
|
||||||
|
Server: ports[5],
|
||||||
|
},
|
||||||
|
ReadyTimeout: 10 * time.Second,
|
||||||
|
Connect: map[string]interface{}{
|
||||||
|
"enabled": true,
|
||||||
|
"ca_config": map[string]interface{}{
|
||||||
|
// const TestClusterID causes import cycle so hard code it here.
|
||||||
|
"cluster_id": "11111111-2222-3333-4444-555555555555",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ReturnPorts: func() {
|
||||||
|
freeport.Return(ports)
|
||||||
|
},
|
||||||
|
Stdout: logBuffer,
|
||||||
|
Stderr: logBuffer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestService is used to serialize a service definition.
|
||||||
|
type TestService struct {
|
||||||
|
ID string `json:",omitempty"`
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
Tags []string `json:",omitempty"`
|
||||||
|
Address string `json:",omitempty"`
|
||||||
|
Port int `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestCheck is used to serialize a check definition.
|
||||||
|
type TestCheck struct {
|
||||||
|
ID string `json:",omitempty"`
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
ServiceID string `json:",omitempty"`
|
||||||
|
TTL string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestKVResponse is what we use to decode KV data.
|
||||||
|
type TestKVResponse struct {
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestServer is the main server wrapper struct.
|
||||||
|
type TestServer struct {
|
||||||
|
cmd *exec.Cmd
|
||||||
|
Config *TestServerConfig
|
||||||
|
|
||||||
|
HTTPAddr string
|
||||||
|
HTTPSAddr string
|
||||||
|
LANAddr string
|
||||||
|
WANAddr string
|
||||||
|
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
tmpdir string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTestServerConfig creates a new TestServer, and makes a call to an optional
|
||||||
|
// callback function to modify the configuration. If there is an error
|
||||||
|
// configuring or starting the server, the server will NOT be running when the
|
||||||
|
// function returns (thus you do not need to stop it).
|
||||||
|
func NewTestServerConfigT(t testing.TB, cb ServerConfigCallback) (*TestServer, error) {
|
||||||
|
path, err := exec.LookPath("consul")
|
||||||
|
if err != nil || path == "" {
|
||||||
|
return nil, fmt.Errorf("consul not found on $PATH - download and install " +
|
||||||
|
"consul or skip this test")
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := "consul"
|
||||||
|
if t != nil {
|
||||||
|
// Use test name for tmpdir if available
|
||||||
|
prefix = strings.Replace(t.Name(), "/", "_", -1)
|
||||||
|
}
|
||||||
|
tmpdir, err := ioutil.TempDir("", prefix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to create tempdir")
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := defaultServerConfig(t)
|
||||||
|
cfg.DataDir = filepath.Join(tmpdir, "data")
|
||||||
|
if cb != nil {
|
||||||
|
cb(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := json.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
cfg.ReturnPorts()
|
||||||
|
os.RemoveAll(tmpdir)
|
||||||
|
return nil, errors.Wrap(err, "failed marshaling json")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("CONFIG JSON: %s", string(b))
|
||||||
|
configFile := filepath.Join(tmpdir, "config.json")
|
||||||
|
if err := ioutil.WriteFile(configFile, b, 0644); err != nil {
|
||||||
|
cfg.ReturnPorts()
|
||||||
|
os.RemoveAll(tmpdir)
|
||||||
|
return nil, errors.Wrap(err, "failed writing config content")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the server
|
||||||
|
args := []string{"agent", "-config-file", configFile}
|
||||||
|
args = append(args, cfg.Args...)
|
||||||
|
cmd := exec.Command("consul", args...)
|
||||||
|
cmd.Stdout = cfg.Stdout
|
||||||
|
cmd.Stderr = cfg.Stderr
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
cfg.ReturnPorts()
|
||||||
|
os.RemoveAll(tmpdir)
|
||||||
|
return nil, errors.Wrap(err, "failed starting command")
|
||||||
|
}
|
||||||
|
|
||||||
|
httpAddr := fmt.Sprintf("127.0.0.1:%d", cfg.Ports.HTTP)
|
||||||
|
client := cleanhttp.DefaultClient()
|
||||||
|
if strings.HasPrefix(cfg.Addresses.HTTP, "unix://") {
|
||||||
|
httpAddr = cfg.Addresses.HTTP
|
||||||
|
tr := cleanhttp.DefaultTransport()
|
||||||
|
tr.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||||
|
return net.Dial("unix", httpAddr[len("unix://"):])
|
||||||
|
}
|
||||||
|
client = &http.Client{Transport: tr}
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &TestServer{
|
||||||
|
Config: cfg,
|
||||||
|
cmd: cmd,
|
||||||
|
|
||||||
|
HTTPAddr: httpAddr,
|
||||||
|
HTTPSAddr: fmt.Sprintf("127.0.0.1:%d", cfg.Ports.HTTPS),
|
||||||
|
LANAddr: fmt.Sprintf("127.0.0.1:%d", cfg.Ports.SerfLan),
|
||||||
|
WANAddr: fmt.Sprintf("127.0.0.1:%d", cfg.Ports.SerfWan),
|
||||||
|
|
||||||
|
HTTPClient: client,
|
||||||
|
|
||||||
|
tmpdir: tmpdir,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the server to be ready
|
||||||
|
if err := server.waitForAPI(); err != nil {
|
||||||
|
if err := server.Stop(); err != nil {
|
||||||
|
t.Logf("server stop failed with: %v", err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return server, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the test Consul server, and removes the Consul data
|
||||||
|
// directory once we are done.
|
||||||
|
func (s *TestServer) Stop() error {
|
||||||
|
defer s.Config.ReturnPorts()
|
||||||
|
defer os.RemoveAll(s.tmpdir)
|
||||||
|
|
||||||
|
// There was no process
|
||||||
|
if s.cmd == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.cmd.Process != nil {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
if err := s.cmd.Process.Kill(); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to kill consul server")
|
||||||
|
}
|
||||||
|
} else { // interrupt is not supported in windows
|
||||||
|
if err := s.cmd.Process.Signal(os.Interrupt); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to kill consul server")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitDone := make(chan error)
|
||||||
|
go func() {
|
||||||
|
waitDone <- s.cmd.Wait()
|
||||||
|
close(waitDone)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// wait for the process to exit to be sure that the data dir can be
|
||||||
|
// deleted on all platforms.
|
||||||
|
select {
|
||||||
|
case err := <-waitDone:
|
||||||
|
return err
|
||||||
|
case <-time.After(10 * time.Second):
|
||||||
|
s.cmd.Process.Signal(syscall.SIGABRT)
|
||||||
|
s.cmd.Wait()
|
||||||
|
return fmt.Errorf("timeout waiting for server to stop gracefully")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForAPI waits for the /status/leader HTTP endpoint to start
|
||||||
|
// responding. This is an indication that the agent has started,
|
||||||
|
// but will likely return before a leader is elected.
|
||||||
|
// Note: We do not check for a successful response status because
|
||||||
|
// we want this function to return without error even when
|
||||||
|
// there's no leader elected.
|
||||||
|
func (s *TestServer) waitForAPI() error {
|
||||||
|
var failed bool
|
||||||
|
|
||||||
|
// This retry replicates the logic of retry.Run to allow for nested retries.
|
||||||
|
// By returning an error we can wrap TestServer creation with retry.Run
|
||||||
|
// in makeClientWithConfig.
|
||||||
|
timer := retry.TwoSeconds()
|
||||||
|
deadline := time.Now().Add(timer.Timeout)
|
||||||
|
for !time.Now().After(deadline) {
|
||||||
|
time.Sleep(timer.Wait)
|
||||||
|
|
||||||
|
url := s.url("/v1/status/leader")
|
||||||
|
resp, err := s.masterGet(url)
|
||||||
|
if err != nil {
|
||||||
|
failed = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
failed = false
|
||||||
|
}
|
||||||
|
if failed {
|
||||||
|
return fmt.Errorf("api unavailable")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitForLeader waits for the Consul server's HTTP API to become
|
||||||
|
// available, and then waits for a known leader and an index of
|
||||||
|
// 2 or more to be observed to confirm leader election is done.
|
||||||
|
func (s *TestServer) WaitForLeader(t *testing.T) {
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
// Query the API and check the status code.
|
||||||
|
url := s.url("/v1/catalog/nodes")
|
||||||
|
resp, err := s.masterGet(url)
|
||||||
|
if err != nil {
|
||||||
|
r.Fatalf("failed http get '%s': %v", url, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := s.requireOK(resp); err != nil {
|
||||||
|
r.Fatal("failed OK response", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have a leader and a node registration.
|
||||||
|
if leader := resp.Header.Get("X-Consul-KnownLeader"); leader != "true" {
|
||||||
|
r.Fatalf("Consul leader status: %#v", leader)
|
||||||
|
}
|
||||||
|
index, err := strconv.ParseInt(resp.Header.Get("X-Consul-Index"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
r.Fatal("bad consul index", err)
|
||||||
|
}
|
||||||
|
if index < 2 {
|
||||||
|
r.Fatal("consul index should be at least 2")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForActiveCARoot waits until the server can return a Connect CA meaning
|
||||||
|
// connect has completed bootstrapping and is ready to use.
|
||||||
|
func (s *TestServer) WaitForActiveCARoot(t *testing.T) {
|
||||||
|
// don't need to fully decode the response
|
||||||
|
type rootsResponse struct {
|
||||||
|
ActiveRootID string
|
||||||
|
TrustDomain string
|
||||||
|
Roots []interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
// Query the API and check the status code.
|
||||||
|
url := s.url("/v1/agent/connect/ca/roots")
|
||||||
|
resp, err := s.masterGet(url)
|
||||||
|
if err != nil {
|
||||||
|
r.Fatalf("failed http get '%s': %v", url, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
// Roots will return an error status until it's been bootstrapped. We could
|
||||||
|
// parse the body and sanity check but that causes either import cycles
|
||||||
|
// since this is used in both `api` and consul test or duplication. The 200
|
||||||
|
// is all we really need to wait for.
|
||||||
|
if err := s.requireOK(resp); err != nil {
|
||||||
|
r.Fatal("failed OK response", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var roots rootsResponse
|
||||||
|
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
if err := dec.Decode(&roots); err != nil {
|
||||||
|
r.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if roots.ActiveRootID == "" || len(roots.Roots) < 1 {
|
||||||
|
r.Fatalf("/v1/agent/connect/ca/roots returned 200 but without roots: %+v", roots)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForSerfCheck ensures we have a node with serfHealth check registered
|
||||||
|
// Behavior mirrors testrpc.WaitForTestAgent but avoids the dependency cycle in api pkg
|
||||||
|
func (s *TestServer) WaitForSerfCheck(t *testing.T) {
|
||||||
|
retry.Run(t, func(r *retry.R) {
|
||||||
|
// Query the API and check the status code.
|
||||||
|
url := s.url("/v1/catalog/nodes?index=0")
|
||||||
|
resp, err := s.masterGet(url)
|
||||||
|
if err != nil {
|
||||||
|
r.Fatal("failed http get", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := s.requireOK(resp); err != nil {
|
||||||
|
r.Fatal("failed OK response", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch for the anti-entropy sync to finish.
|
||||||
|
var payload []map[string]interface{}
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
if err := dec.Decode(&payload); err != nil {
|
||||||
|
r.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(payload) < 1 {
|
||||||
|
r.Fatal("No nodes")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the serfHealth check is registered
|
||||||
|
url = s.url(fmt.Sprintf("/v1/health/node/%s", payload[0]["Node"]))
|
||||||
|
resp, err = s.masterGet(url)
|
||||||
|
if err != nil {
|
||||||
|
r.Fatal("failed http get", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err := s.requireOK(resp); err != nil {
|
||||||
|
r.Fatal("failed OK response", err)
|
||||||
|
}
|
||||||
|
dec = json.NewDecoder(resp.Body)
|
||||||
|
if err = dec.Decode(&payload); err != nil {
|
||||||
|
r.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, check := range payload {
|
||||||
|
if check["CheckID"].(string) == "serfHealth" {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
r.Fatal("missing serfHealth registration")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TestServer) masterGet(url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if s.Config.ACL.Tokens.Master != "" {
|
||||||
|
req.Header.Set("x-consul-token", s.Config.ACL.Tokens.Master)
|
||||||
|
}
|
||||||
|
return s.HTTPClient.Do(req)
|
||||||
|
}
|
256
vendor/github.com/hashicorp/consul/sdk/testutil/server_methods.go
generated
vendored
Normal file
256
vendor/github.com/hashicorp/consul/sdk/testutil/server_methods.go
generated
vendored
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// copied from testutil to break circular dependency
|
||||||
|
const (
|
||||||
|
HealthAny = "any"
|
||||||
|
HealthPassing = "passing"
|
||||||
|
HealthWarning = "warning"
|
||||||
|
HealthCritical = "critical"
|
||||||
|
HealthMaint = "maintenance"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JoinLAN is used to join local datacenters together.
|
||||||
|
func (s *TestServer) JoinLAN(t *testing.T, addr string) {
|
||||||
|
resp := s.put(t, "/v1/agent/join/"+addr, nil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// JoinWAN is used to join remote datacenters together.
|
||||||
|
func (s *TestServer) JoinWAN(t *testing.T, addr string) {
|
||||||
|
resp := s.put(t, "/v1/agent/join/"+addr+"?wan=1", nil)
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKV sets an individual key in the K/V store.
|
||||||
|
func (s *TestServer) SetKV(t *testing.T, key string, val []byte) {
|
||||||
|
resp := s.put(t, "/v1/kv/"+key, bytes.NewBuffer(val))
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetKVString sets an individual key in the K/V store, but accepts a string
|
||||||
|
// instead of []byte.
|
||||||
|
func (s *TestServer) SetKVString(t *testing.T, key string, val string) {
|
||||||
|
resp := s.put(t, "/v1/kv/"+key, bytes.NewBufferString(val))
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKV retrieves a single key and returns its value
|
||||||
|
func (s *TestServer) GetKV(t *testing.T, key string) []byte {
|
||||||
|
resp := s.get(t, "/v1/kv/"+key)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read body: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []*TestKVResponse
|
||||||
|
if err := json.Unmarshal(raw, &result); err != nil {
|
||||||
|
t.Fatalf("failed to unmarshal: %s", err)
|
||||||
|
}
|
||||||
|
if len(result) < 1 {
|
||||||
|
t.Fatalf("key does not exist: %s", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := base64.StdEncoding.DecodeString(result[0].Value)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to base64 decode: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKVString retrieves a value from the store, but returns as a string instead
|
||||||
|
// of []byte.
|
||||||
|
func (s *TestServer) GetKVString(t *testing.T, key string) string {
|
||||||
|
return string(s.GetKV(t, key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopulateKV fills the Consul KV with data from a generic map.
|
||||||
|
func (s *TestServer) PopulateKV(t *testing.T, data map[string][]byte) {
|
||||||
|
for k, v := range data {
|
||||||
|
s.SetKV(t, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListKV returns a list of keys present in the KV store. This will list all
|
||||||
|
// keys under the given prefix recursively and return them as a slice.
|
||||||
|
func (s *TestServer) ListKV(t *testing.T, prefix string) []string {
|
||||||
|
resp := s.get(t, "/v1/kv/"+prefix+"?keys")
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
raw, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read body: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []string
|
||||||
|
if err := json.Unmarshal(raw, &result); err != nil {
|
||||||
|
t.Fatalf("failed to unmarshal: %s", err)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddService adds a new service to the Consul instance. It also
|
||||||
|
// automatically adds a health check with the given status, which
|
||||||
|
// can be one of "passing", "warning", or "critical".
|
||||||
|
func (s *TestServer) AddService(t *testing.T, name, status string, tags []string) {
|
||||||
|
s.AddAddressableService(t, name, status, "", 0, tags) // set empty address and 0 as port for non-accessible service
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAddressableService adds a new service to the Consul instance by
|
||||||
|
// passing "address" and "port". It is helpful when you need to prepare a fakeService
|
||||||
|
// that maybe accessed with in target source code.
|
||||||
|
// It also automatically adds a health check with the given status, which
|
||||||
|
// can be one of "passing", "warning", or "critical", just like `AddService` does.
|
||||||
|
func (s *TestServer) AddAddressableService(t *testing.T, name, status, address string, port int, tags []string) {
|
||||||
|
svc := &TestService{
|
||||||
|
Name: name,
|
||||||
|
Tags: tags,
|
||||||
|
Address: address,
|
||||||
|
Port: port,
|
||||||
|
}
|
||||||
|
payload, err := s.encodePayload(svc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s.put(t, "/v1/agent/service/register", payload)
|
||||||
|
|
||||||
|
chkName := "service:" + name
|
||||||
|
chk := &TestCheck{
|
||||||
|
Name: chkName,
|
||||||
|
ServiceID: name,
|
||||||
|
TTL: "10m",
|
||||||
|
}
|
||||||
|
payload, err = s.encodePayload(chk)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s.put(t, "/v1/agent/check/register", payload)
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case HealthPassing:
|
||||||
|
s.put(t, "/v1/agent/check/pass/"+chkName, nil)
|
||||||
|
case HealthWarning:
|
||||||
|
s.put(t, "/v1/agent/check/warn/"+chkName, nil)
|
||||||
|
case HealthCritical:
|
||||||
|
s.put(t, "/v1/agent/check/fail/"+chkName, nil)
|
||||||
|
default:
|
||||||
|
t.Fatalf("Unrecognized status: %s", status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCheck adds a check to the Consul instance. If the serviceID is
|
||||||
|
// left empty (""), then the check will be associated with the node.
|
||||||
|
// The check status may be "passing", "warning", or "critical".
|
||||||
|
func (s *TestServer) AddCheck(t *testing.T, name, serviceID, status string) {
|
||||||
|
chk := &TestCheck{
|
||||||
|
ID: name,
|
||||||
|
Name: name,
|
||||||
|
TTL: "10m",
|
||||||
|
}
|
||||||
|
if serviceID != "" {
|
||||||
|
chk.ServiceID = serviceID
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, err := s.encodePayload(chk)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s.put(t, "/v1/agent/check/register", payload)
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case HealthPassing:
|
||||||
|
s.put(t, "/v1/agent/check/pass/"+name, nil)
|
||||||
|
case HealthWarning:
|
||||||
|
s.put(t, "/v1/agent/check/warn/"+name, nil)
|
||||||
|
case HealthCritical:
|
||||||
|
s.put(t, "/v1/agent/check/fail/"+name, nil)
|
||||||
|
default:
|
||||||
|
t.Fatalf("Unrecognized status: %s", status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// put performs a new HTTP PUT request.
|
||||||
|
func (s *TestServer) put(t *testing.T, path string, body io.Reader) *http.Response {
|
||||||
|
req, err := http.NewRequest("PUT", s.url(path), body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create PUT request: %s", err)
|
||||||
|
}
|
||||||
|
resp, err := s.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to make PUT request: %s", err)
|
||||||
|
}
|
||||||
|
if err := s.requireOK(resp); err != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
t.Fatalf("not OK PUT: %s", err)
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// get performs a new HTTP GET request.
|
||||||
|
func (s *TestServer) get(t *testing.T, path string) *http.Response {
|
||||||
|
resp, err := s.HTTPClient.Get(s.url(path))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create GET request: %s", err)
|
||||||
|
}
|
||||||
|
if err := s.requireOK(resp); err != nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
t.Fatalf("not OK GET: %s", err)
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodePayload returns a new io.Reader wrapping the encoded contents
|
||||||
|
// of the payload, suitable for passing directly to a new request.
|
||||||
|
func (s *TestServer) encodePayload(payload interface{}) (io.Reader, error) {
|
||||||
|
var encoded bytes.Buffer
|
||||||
|
enc := json.NewEncoder(&encoded)
|
||||||
|
if err := enc.Encode(payload); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to encode payload")
|
||||||
|
}
|
||||||
|
return &encoded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// url is a helper function which takes a relative URL and
|
||||||
|
// makes it into a proper URL against the local Consul server.
|
||||||
|
func (s *TestServer) url(path string) string {
|
||||||
|
if s == nil {
|
||||||
|
log.Fatal("s is nil")
|
||||||
|
}
|
||||||
|
if s.Config == nil {
|
||||||
|
log.Fatal("s.Config is nil")
|
||||||
|
}
|
||||||
|
if s.Config.Ports == nil {
|
||||||
|
log.Fatal("s.Config.Ports is nil")
|
||||||
|
}
|
||||||
|
if s.Config.Ports.HTTP == 0 {
|
||||||
|
log.Fatal("s.Config.Ports.HTTP is 0")
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
log.Fatal("path is empty")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("http://127.0.0.1:%d%s", s.Config.Ports.HTTP, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// requireOK checks the HTTP response code and ensures it is acceptable.
|
||||||
|
func (s *TestServer) requireOK(resp *http.Response) error {
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
|
return fmt.Errorf("Bad status code: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
65
vendor/github.com/hashicorp/consul/sdk/testutil/server_wrapper.go
generated
vendored
Normal file
65
vendor/github.com/hashicorp/consul/sdk/testutil/server_wrapper.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type WrappedServer struct {
|
||||||
|
s *TestServer
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap wraps the test server in a `testing.t` for convenience.
|
||||||
|
//
|
||||||
|
// For example, the following code snippets are equivalent.
|
||||||
|
//
|
||||||
|
// server.JoinLAN(t, "1.2.3.4")
|
||||||
|
// server.Wrap(t).JoinLAN("1.2.3.4")
|
||||||
|
//
|
||||||
|
// This is useful when you are calling multiple functions and save the wrapped
|
||||||
|
// value as another variable to reduce the inclusion of "t".
|
||||||
|
func (s *TestServer) Wrap(t *testing.T) *WrappedServer {
|
||||||
|
return &WrappedServer{s, t}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) JoinLAN(addr string) {
|
||||||
|
w.s.JoinLAN(w.t, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) JoinWAN(addr string) {
|
||||||
|
w.s.JoinWAN(w.t, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) SetKV(key string, val []byte) {
|
||||||
|
w.s.SetKV(w.t, key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) SetKVString(key string, val string) {
|
||||||
|
w.s.SetKVString(w.t, key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) GetKV(key string) []byte {
|
||||||
|
return w.s.GetKV(w.t, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) GetKVString(key string) string {
|
||||||
|
return w.s.GetKVString(w.t, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) PopulateKV(data map[string][]byte) {
|
||||||
|
w.s.PopulateKV(w.t, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) ListKV(prefix string) []string {
|
||||||
|
return w.s.ListKV(w.t, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) AddService(name, status string, tags []string) {
|
||||||
|
w.s.AddService(w.t, name, status, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) AddAddressableService(name, status, address string, port int, tags []string) {
|
||||||
|
w.s.AddAddressableService(w.t, name, status, address, port, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *WrappedServer) AddCheck(name, serviceID, status string) {
|
||||||
|
w.s.AddCheck(w.t, name, serviceID, status)
|
||||||
|
}
|
62
vendor/github.com/hashicorp/consul/sdk/testutil/testlog.go
generated
vendored
Normal file
62
vendor/github.com/hashicorp/consul/sdk/testutil/testlog.go
generated
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Logger(t testing.TB) hclog.InterceptLogger {
|
||||||
|
return LoggerWithOutput(t, NewLogBuffer(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoggerWithOutput(t testing.TB, output io.Writer) hclog.InterceptLogger {
|
||||||
|
return hclog.NewInterceptLogger(&hclog.LoggerOptions{
|
||||||
|
Name: t.Name(),
|
||||||
|
Level: hclog.Trace,
|
||||||
|
Output: output,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendTestLogsToStdout = os.Getenv("NOLOGBUFFER") == "1"
|
||||||
|
|
||||||
|
// NewLogBuffer returns an io.Writer which buffers all writes. When the test
|
||||||
|
// ends, t.Failed is checked. If the test has failed all log output is printed
|
||||||
|
// to stdout.
|
||||||
|
//
|
||||||
|
// Set the env var NOLOGBUFFER=1 to disable buffering, resulting in all log
|
||||||
|
// output being written immediately to stdout.
|
||||||
|
func NewLogBuffer(t CleanupT) io.Writer {
|
||||||
|
if sendTestLogsToStdout {
|
||||||
|
return os.Stdout
|
||||||
|
}
|
||||||
|
buf := &logBuffer{buf: new(bytes.Buffer)}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if t.Failed() {
|
||||||
|
buf.Lock()
|
||||||
|
defer buf.Unlock()
|
||||||
|
buf.buf.WriteTo(os.Stdout)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
type CleanupT interface {
|
||||||
|
Cleanup(f func())
|
||||||
|
Failed() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type logBuffer struct {
|
||||||
|
buf *bytes.Buffer
|
||||||
|
sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lb *logBuffer) Write(p []byte) (n int, err error) {
|
||||||
|
lb.Lock()
|
||||||
|
defer lb.Unlock()
|
||||||
|
return lb.buf.Write(p)
|
||||||
|
}
|
12
vendor/github.com/hashicorp/go-retryablehttp/.travis.yml
generated
vendored
12
vendor/github.com/hashicorp/go-retryablehttp/.travis.yml
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
sudo: false
|
|
||||||
|
|
||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.12.4
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
|
|
||||||
script: make updatedeps test
|
|
15
vendor/github.com/hashicorp/go-retryablehttp/README.md
generated
vendored
15
vendor/github.com/hashicorp/go-retryablehttp/README.md
generated
vendored
@ -25,6 +25,8 @@ fails so that the full request can be attempted again. See the
|
|||||||
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more
|
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
Version 0.6.0 and before are compatible with Go prior to 1.12. From 0.6.1 onward, Go 1.12+ is required.
|
||||||
|
|
||||||
Example Use
|
Example Use
|
||||||
===========
|
===========
|
||||||
|
|
||||||
@ -42,5 +44,18 @@ The returned response object is an `*http.Response`, the same thing you would
|
|||||||
usually get from `net/http`. Had the request failed one or more times, the above
|
usually get from `net/http`. Had the request failed one or more times, the above
|
||||||
call would block and retry with exponential backoff.
|
call would block and retry with exponential backoff.
|
||||||
|
|
||||||
|
## Getting a stdlib `*http.Client` with retries
|
||||||
|
|
||||||
|
It's possible to convert a `*retryablehttp.Client` directly to a `*http.Client`.
|
||||||
|
This makes use of retryablehttp broadly applicable with minimal effort. Simply
|
||||||
|
configure a `*retryablehttp.Client` as you wish, and then call `StandardClient()`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
retryClient := retryablehttp.NewClient()
|
||||||
|
retryClient.RetryMax = 10
|
||||||
|
|
||||||
|
standardClient := retryClient.StandardClient() // *http.Client
|
||||||
|
```
|
||||||
|
|
||||||
For more usage and examples see the
|
For more usage and examples see the
|
||||||
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp).
|
[godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp).
|
||||||
|
483
vendor/github.com/hashicorp/go-retryablehttp/client.go
generated
vendored
483
vendor/github.com/hashicorp/go-retryablehttp/client.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// The retryablehttp package provides a familiar HTTP client interface with
|
// Package retryablehttp provides a familiar HTTP client interface with
|
||||||
// automatic retries and exponential backoff. It is a thin wrapper over the
|
// automatic retries and exponential backoff. It is a thin wrapper over the
|
||||||
// standard net/http client library and exposes nearly the same public API.
|
// standard net/http client library and exposes nearly the same public API.
|
||||||
// This makes retryablehttp very easy to drop into existing programs.
|
// This makes retryablehttp very easy to drop into existing programs.
|
||||||
@ -24,6 +24,7 @@ package retryablehttp
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -33,7 +34,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
||||||
@ -45,6 +49,9 @@ var (
|
|||||||
defaultRetryWaitMax = 30 * time.Second
|
defaultRetryWaitMax = 30 * time.Second
|
||||||
defaultRetryMax = 4
|
defaultRetryMax = 4
|
||||||
|
|
||||||
|
// defaultLogger is the logger provided with defaultClient
|
||||||
|
defaultLogger = log.New(os.Stderr, "", log.LstdFlags)
|
||||||
|
|
||||||
// defaultClient is used for performing requests without explicitly making
|
// defaultClient is used for performing requests without explicitly making
|
||||||
// a new client. It is purposely private to avoid modifications.
|
// a new client. It is purposely private to avoid modifications.
|
||||||
defaultClient = NewClient()
|
defaultClient = NewClient()
|
||||||
@ -52,6 +59,16 @@ var (
|
|||||||
// We need to consume response bodies to maintain http connections, but
|
// We need to consume response bodies to maintain http connections, but
|
||||||
// limit the size we consume to respReadLimit.
|
// limit the size we consume to respReadLimit.
|
||||||
respReadLimit = int64(4096)
|
respReadLimit = int64(4096)
|
||||||
|
|
||||||
|
// A regular expression to match the error returned by net/http when the
|
||||||
|
// configured number of redirects is exhausted. This error isn't typed
|
||||||
|
// specifically so we resort to matching on the error string.
|
||||||
|
redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`)
|
||||||
|
|
||||||
|
// A regular expression to match the error returned by net/http when the
|
||||||
|
// scheme specified in the URL is invalid. This error isn't typed
|
||||||
|
// specifically so we resort to matching on the error string.
|
||||||
|
schemeErrorRe = regexp.MustCompile(`unsupported protocol scheme`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReaderFunc is the type of function that can be given natively to NewRequest
|
// ReaderFunc is the type of function that can be given natively to NewRequest
|
||||||
@ -103,95 +120,127 @@ func (r *Request) BodyBytes() ([]byte, error) {
|
|||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBody allows setting the request body.
|
||||||
|
//
|
||||||
|
// It is useful if a new body needs to be set without constructing a new Request.
|
||||||
|
func (r *Request) SetBody(rawBody interface{}) error {
|
||||||
|
bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r.body = bodyReader
|
||||||
|
r.ContentLength = contentLength
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTo allows copying the request body into a writer.
|
||||||
|
//
|
||||||
|
// It writes data to w until there's no more data to write or
|
||||||
|
// when an error occurs. The return int64 value is the number of bytes
|
||||||
|
// written. Any error encountered during the write is also returned.
|
||||||
|
// The signature matches io.WriterTo interface.
|
||||||
|
func (r *Request) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
body, err := r.body()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if c, ok := body.(io.Closer); ok {
|
||||||
|
defer c.Close()
|
||||||
|
}
|
||||||
|
return io.Copy(w, body)
|
||||||
|
}
|
||||||
|
|
||||||
func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, error) {
|
func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, error) {
|
||||||
var bodyReader ReaderFunc
|
var bodyReader ReaderFunc
|
||||||
var contentLength int64
|
var contentLength int64
|
||||||
|
|
||||||
if rawBody != nil {
|
switch body := rawBody.(type) {
|
||||||
switch body := rawBody.(type) {
|
// If they gave us a function already, great! Use it.
|
||||||
// If they gave us a function already, great! Use it.
|
case ReaderFunc:
|
||||||
case ReaderFunc:
|
bodyReader = body
|
||||||
bodyReader = body
|
tmp, err := body()
|
||||||
tmp, err := body()
|
if err != nil {
|
||||||
if err != nil {
|
return nil, 0, err
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
if lr, ok := tmp.(LenReader); ok {
|
|
||||||
contentLength = int64(lr.Len())
|
|
||||||
}
|
|
||||||
if c, ok := tmp.(io.Closer); ok {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
case func() (io.Reader, error):
|
|
||||||
bodyReader = body
|
|
||||||
tmp, err := body()
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
if lr, ok := tmp.(LenReader); ok {
|
|
||||||
contentLength = int64(lr.Len())
|
|
||||||
}
|
|
||||||
if c, ok := tmp.(io.Closer); ok {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a regular byte slice, we can read it over and over via new
|
|
||||||
// readers
|
|
||||||
case []byte:
|
|
||||||
buf := body
|
|
||||||
bodyReader = func() (io.Reader, error) {
|
|
||||||
return bytes.NewReader(buf), nil
|
|
||||||
}
|
|
||||||
contentLength = int64(len(buf))
|
|
||||||
|
|
||||||
// If a bytes.Buffer we can read the underlying byte slice over and
|
|
||||||
// over
|
|
||||||
case *bytes.Buffer:
|
|
||||||
buf := body
|
|
||||||
bodyReader = func() (io.Reader, error) {
|
|
||||||
return bytes.NewReader(buf.Bytes()), nil
|
|
||||||
}
|
|
||||||
contentLength = int64(buf.Len())
|
|
||||||
|
|
||||||
// We prioritize *bytes.Reader here because we don't really want to
|
|
||||||
// deal with it seeking so want it to match here instead of the
|
|
||||||
// io.ReadSeeker case.
|
|
||||||
case *bytes.Reader:
|
|
||||||
buf, err := ioutil.ReadAll(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
bodyReader = func() (io.Reader, error) {
|
|
||||||
return bytes.NewReader(buf), nil
|
|
||||||
}
|
|
||||||
contentLength = int64(len(buf))
|
|
||||||
|
|
||||||
// Compat case
|
|
||||||
case io.ReadSeeker:
|
|
||||||
raw := body
|
|
||||||
bodyReader = func() (io.Reader, error) {
|
|
||||||
_, err := raw.Seek(0, 0)
|
|
||||||
return ioutil.NopCloser(raw), err
|
|
||||||
}
|
|
||||||
if lr, ok := raw.(LenReader); ok {
|
|
||||||
contentLength = int64(lr.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read all in so we can reset
|
|
||||||
case io.Reader:
|
|
||||||
buf, err := ioutil.ReadAll(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
bodyReader = func() (io.Reader, error) {
|
|
||||||
return bytes.NewReader(buf), nil
|
|
||||||
}
|
|
||||||
contentLength = int64(len(buf))
|
|
||||||
|
|
||||||
default:
|
|
||||||
return nil, 0, fmt.Errorf("cannot handle type %T", rawBody)
|
|
||||||
}
|
}
|
||||||
|
if lr, ok := tmp.(LenReader); ok {
|
||||||
|
contentLength = int64(lr.Len())
|
||||||
|
}
|
||||||
|
if c, ok := tmp.(io.Closer); ok {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
case func() (io.Reader, error):
|
||||||
|
bodyReader = body
|
||||||
|
tmp, err := body()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if lr, ok := tmp.(LenReader); ok {
|
||||||
|
contentLength = int64(lr.Len())
|
||||||
|
}
|
||||||
|
if c, ok := tmp.(io.Closer); ok {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a regular byte slice, we can read it over and over via new
|
||||||
|
// readers
|
||||||
|
case []byte:
|
||||||
|
buf := body
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(len(buf))
|
||||||
|
|
||||||
|
// If a bytes.Buffer we can read the underlying byte slice over and
|
||||||
|
// over
|
||||||
|
case *bytes.Buffer:
|
||||||
|
buf := body
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf.Bytes()), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(buf.Len())
|
||||||
|
|
||||||
|
// We prioritize *bytes.Reader here because we don't really want to
|
||||||
|
// deal with it seeking so want it to match here instead of the
|
||||||
|
// io.ReadSeeker case.
|
||||||
|
case *bytes.Reader:
|
||||||
|
buf, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(len(buf))
|
||||||
|
|
||||||
|
// Compat case
|
||||||
|
case io.ReadSeeker:
|
||||||
|
raw := body
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
_, err := raw.Seek(0, 0)
|
||||||
|
return ioutil.NopCloser(raw), err
|
||||||
|
}
|
||||||
|
if lr, ok := raw.(LenReader); ok {
|
||||||
|
contentLength = int64(lr.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all in so we can reset
|
||||||
|
case io.Reader:
|
||||||
|
buf, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
bodyReader = func() (io.Reader, error) {
|
||||||
|
return bytes.NewReader(buf), nil
|
||||||
|
}
|
||||||
|
contentLength = int64(len(buf))
|
||||||
|
|
||||||
|
// No body provided, nothing to do
|
||||||
|
case nil:
|
||||||
|
|
||||||
|
// Unrecognized type
|
||||||
|
default:
|
||||||
|
return nil, 0, fmt.Errorf("cannot handle type %T", rawBody)
|
||||||
}
|
}
|
||||||
return bodyReader, contentLength, nil
|
return bodyReader, contentLength, nil
|
||||||
}
|
}
|
||||||
@ -228,6 +277,28 @@ type Logger interface {
|
|||||||
Printf(string, ...interface{})
|
Printf(string, ...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LeveledLogger is an interface that can be implemented by any logger or a
|
||||||
|
// logger wrapper to provide leveled logging. The methods accept a message
|
||||||
|
// string and a variadic number of key-value pairs. For log.Printf style
|
||||||
|
// formatting where message string contains a format specifier, use Logger
|
||||||
|
// interface.
|
||||||
|
type LeveledLogger interface {
|
||||||
|
Error(msg string, keysAndValues ...interface{})
|
||||||
|
Info(msg string, keysAndValues ...interface{})
|
||||||
|
Debug(msg string, keysAndValues ...interface{})
|
||||||
|
Warn(msg string, keysAndValues ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// hookLogger adapts an LeveledLogger to Logger for use by the existing hook functions
|
||||||
|
// without changing the API.
|
||||||
|
type hookLogger struct {
|
||||||
|
LeveledLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h hookLogger) Printf(s string, args ...interface{}) {
|
||||||
|
h.Info(fmt.Sprintf(s, args...))
|
||||||
|
}
|
||||||
|
|
||||||
// RequestLogHook allows a function to run before each retry. The HTTP
|
// RequestLogHook allows a function to run before each retry. The HTTP
|
||||||
// request which will be made, and the retry number (0 for the initial
|
// request which will be made, and the retry number (0 for the initial
|
||||||
// request) are available to users. The internal logger is exposed to
|
// request) are available to users. The internal logger is exposed to
|
||||||
@ -247,7 +318,7 @@ type ResponseLogHook func(Logger, *http.Response)
|
|||||||
// and returns the response to the caller. If CheckRetry returns an error,
|
// and returns the response to the caller. If CheckRetry returns an error,
|
||||||
// that error value is returned in lieu of the error from the request. The
|
// that error value is returned in lieu of the error from the request. The
|
||||||
// Client will close any response body when retrying, but if the retry is
|
// Client will close any response body when retrying, but if the retry is
|
||||||
// aborted it is up to the CheckResponse callback to properly close any
|
// aborted it is up to the CheckRetry callback to properly close any
|
||||||
// response body before returning.
|
// response body before returning.
|
||||||
type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error)
|
type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error)
|
||||||
|
|
||||||
@ -266,7 +337,7 @@ type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Resp
|
|||||||
// like automatic retries to tolerate minor outages.
|
// like automatic retries to tolerate minor outages.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
HTTPClient *http.Client // Internal HTTP client.
|
HTTPClient *http.Client // Internal HTTP client.
|
||||||
Logger Logger // Customer logger instance.
|
Logger interface{} // Customer logger instance. Can be either Logger or LeveledLogger
|
||||||
|
|
||||||
RetryWaitMin time.Duration // Minimum time to wait
|
RetryWaitMin time.Duration // Minimum time to wait
|
||||||
RetryWaitMax time.Duration // Maximum time to wait
|
RetryWaitMax time.Duration // Maximum time to wait
|
||||||
@ -289,13 +360,16 @@ type Client struct {
|
|||||||
|
|
||||||
// ErrorHandler specifies the custom error handler to use, if any
|
// ErrorHandler specifies the custom error handler to use, if any
|
||||||
ErrorHandler ErrorHandler
|
ErrorHandler ErrorHandler
|
||||||
|
|
||||||
|
loggerInit sync.Once
|
||||||
|
clientInit sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a new Client with default settings.
|
// NewClient creates a new Client with default settings.
|
||||||
func NewClient() *Client {
|
func NewClient() *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
HTTPClient: cleanhttp.DefaultClient(),
|
HTTPClient: cleanhttp.DefaultPooledClient(),
|
||||||
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
Logger: defaultLogger,
|
||||||
RetryWaitMin: defaultRetryWaitMin,
|
RetryWaitMin: defaultRetryWaitMin,
|
||||||
RetryWaitMax: defaultRetryWaitMax,
|
RetryWaitMax: defaultRetryWaitMax,
|
||||||
RetryMax: defaultRetryMax,
|
RetryMax: defaultRetryMax,
|
||||||
@ -304,6 +378,24 @@ func NewClient() *Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) logger() interface{} {
|
||||||
|
c.loggerInit.Do(func() {
|
||||||
|
if c.Logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch c.Logger.(type) {
|
||||||
|
case Logger, LeveledLogger:
|
||||||
|
// ok
|
||||||
|
default:
|
||||||
|
// This should happen in dev when they are setting Logger and work on code, not in prod.
|
||||||
|
panic(fmt.Sprintf("invalid logger type passed, must be Logger or LeveledLogger, was %T", c.Logger))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return c.Logger
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which
|
// DefaultRetryPolicy provides a default callback for Client.CheckRetry, which
|
||||||
// will retry on connection errors and server errors.
|
// will retry on connection errors and server errors.
|
||||||
func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
||||||
@ -313,8 +405,34 @@ func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
if v, ok := err.(*url.Error); ok {
|
||||||
|
// Don't retry if the error was due to too many redirects.
|
||||||
|
if redirectsErrorRe.MatchString(v.Error()) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't retry if the error was due to an invalid protocol scheme.
|
||||||
|
if schemeErrorRe.MatchString(v.Error()) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't retry if the error was due to TLS cert verification failure.
|
||||||
|
if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The error is likely recoverable so retry.
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 429 Too Many Requests is recoverable. Sometimes the server puts
|
||||||
|
// a Retry-After response header to indicate when the server is
|
||||||
|
// available to start processing request from client.
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Check the response code. We retry on 500-range responses to allow
|
// Check the response code. We retry on 500-range responses to allow
|
||||||
// the server time to recover, as 500's are typically not permanent
|
// the server time to recover, as 500's are typically not permanent
|
||||||
// errors and may relate to outages on the server side. This will catch
|
// errors and may relate to outages on the server side. This will catch
|
||||||
@ -326,10 +444,66 @@ func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bo
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorPropagatedRetryPolicy is the same as DefaultRetryPolicy, except it
|
||||||
|
// propagates errors back instead of returning nil. This allows you to inspect
|
||||||
|
// why it decided to retry or not.
|
||||||
|
func ErrorPropagatedRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
|
||||||
|
// do not retry on context.Canceled or context.DeadlineExceeded
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return false, ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if v, ok := err.(*url.Error); ok {
|
||||||
|
// Don't retry if the error was due to too many redirects.
|
||||||
|
if redirectsErrorRe.MatchString(v.Error()) {
|
||||||
|
return false, v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't retry if the error was due to an invalid protocol scheme.
|
||||||
|
if schemeErrorRe.MatchString(v.Error()) {
|
||||||
|
return false, v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't retry if the error was due to TLS cert verification failure.
|
||||||
|
if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
|
||||||
|
return false, v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The error is likely recoverable so retry.
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the response code. We retry on 500-range responses to allow
|
||||||
|
// the server time to recover, as 500's are typically not permanent
|
||||||
|
// errors and may relate to outages on the server side. This will catch
|
||||||
|
// invalid response codes as well, like 0 and 999.
|
||||||
|
if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != 501) {
|
||||||
|
return true, fmt.Errorf("unexpected HTTP status %s", resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultBackoff provides a default callback for Client.Backoff which
|
// DefaultBackoff provides a default callback for Client.Backoff which
|
||||||
// will perform exponential backoff based on the attempt number and limited
|
// will perform exponential backoff based on the attempt number and limited
|
||||||
// by the provided minimum and maximum durations.
|
// by the provided minimum and maximum durations.
|
||||||
|
//
|
||||||
|
// It also tries to parse Retry-After response header when a http.StatusTooManyRequests
|
||||||
|
// (HTTP Code 429) is found in the resp parameter. Hence it will return the number of
|
||||||
|
// seconds the server states it may be ready to process more requests from this client.
|
||||||
func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
|
func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration {
|
||||||
|
if resp != nil {
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
if s, ok := resp.Header["Retry-After"]; ok {
|
||||||
|
if sleep, err := strconv.ParseInt(s[0], 10, 64); err == nil {
|
||||||
|
return time.Second * time.Duration(sleep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mult := math.Pow(2, float64(attemptNum)) * float64(min)
|
mult := math.Pow(2, float64(attemptNum)) * float64(min)
|
||||||
sleep := time.Duration(mult)
|
sleep := time.Duration(mult)
|
||||||
if float64(sleep) != mult || sleep > max {
|
if float64(sleep) != mult || sleep > max {
|
||||||
@ -342,7 +516,7 @@ func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response)
|
|||||||
// perform linear backoff based on the attempt number and with jitter to
|
// perform linear backoff based on the attempt number and with jitter to
|
||||||
// prevent a thundering herd.
|
// prevent a thundering herd.
|
||||||
//
|
//
|
||||||
// min and max here are *not* absolute values. The number to be multipled by
|
// min and max here are *not* absolute values. The number to be multiplied by
|
||||||
// the attempt number will be chosen at random from between them, thus they are
|
// the attempt number will be chosen at random from between them, thus they are
|
||||||
// bounding the jitter.
|
// bounding the jitter.
|
||||||
//
|
//
|
||||||
@ -385,20 +559,38 @@ func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Respo
|
|||||||
|
|
||||||
// Do wraps calling an HTTP method with retries.
|
// Do wraps calling an HTTP method with retries.
|
||||||
func (c *Client) Do(req *Request) (*http.Response, error) {
|
func (c *Client) Do(req *Request) (*http.Response, error) {
|
||||||
if c.Logger != nil {
|
c.clientInit.Do(func() {
|
||||||
c.Logger.Printf("[DEBUG] %s %s", req.Method, req.URL)
|
if c.HTTPClient == nil {
|
||||||
|
c.HTTPClient = cleanhttp.DefaultPooledClient()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
logger := c.logger()
|
||||||
|
|
||||||
|
if logger != nil {
|
||||||
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Debug("performing request", "method", req.Method, "url", req.URL)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[DEBUG] %s %s", req.Method, req.URL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
var err error
|
var attempt int
|
||||||
|
var shouldRetry bool
|
||||||
|
var doErr, checkErr error
|
||||||
|
|
||||||
for i := 0; ; i++ {
|
for i := 0; ; i++ {
|
||||||
|
attempt++
|
||||||
|
|
||||||
var code int // HTTP response code
|
var code int // HTTP response code
|
||||||
|
|
||||||
// Always rewind the request body when non-nil.
|
// Always rewind the request body when non-nil.
|
||||||
if req.body != nil {
|
if req.body != nil {
|
||||||
body, err := req.body()
|
body, err := req.body()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
c.HTTPClient.CloseIdleConnections()
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
if c, ok := body.(io.ReadCloser); ok {
|
if c, ok := body.(io.ReadCloser); ok {
|
||||||
@ -409,40 +601,53 @@ func (c *Client) Do(req *Request) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if c.RequestLogHook != nil {
|
if c.RequestLogHook != nil {
|
||||||
c.RequestLogHook(c.Logger, req.Request, i)
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
c.RequestLogHook(hookLogger{v}, req.Request, i)
|
||||||
|
case Logger:
|
||||||
|
c.RequestLogHook(v, req.Request, i)
|
||||||
|
default:
|
||||||
|
c.RequestLogHook(nil, req.Request, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt the request
|
// Attempt the request
|
||||||
resp, err = c.HTTPClient.Do(req.Request)
|
resp, doErr = c.HTTPClient.Do(req.Request)
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
code = resp.StatusCode
|
code = resp.StatusCode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we should continue with retries.
|
// Check if we should continue with retries.
|
||||||
checkOK, checkErr := c.CheckRetry(req.Context(), resp, err)
|
shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, doErr)
|
||||||
|
|
||||||
if err != nil {
|
if doErr != nil {
|
||||||
if c.Logger != nil {
|
switch v := logger.(type) {
|
||||||
c.Logger.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, err)
|
case LeveledLogger:
|
||||||
|
v.Error("request failed", "error", doErr, "method", req.Method, "url", req.URL)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[ERR] %s %s request failed: %v", req.Method, req.URL, doErr)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Call this here to maintain the behavior of logging all requests,
|
// Call this here to maintain the behavior of logging all requests,
|
||||||
// even if CheckRetry signals to stop.
|
// even if CheckRetry signals to stop.
|
||||||
if c.ResponseLogHook != nil {
|
if c.ResponseLogHook != nil {
|
||||||
// Call the response logger function if provided.
|
// Call the response logger function if provided.
|
||||||
c.ResponseLogHook(c.Logger, resp)
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
c.ResponseLogHook(hookLogger{v}, resp)
|
||||||
|
case Logger:
|
||||||
|
c.ResponseLogHook(v, resp)
|
||||||
|
default:
|
||||||
|
c.ResponseLogHook(nil, resp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now decide if we should continue.
|
if !shouldRetry {
|
||||||
if !checkOK {
|
break
|
||||||
if checkErr != nil {
|
|
||||||
err = checkErr
|
|
||||||
}
|
|
||||||
return resp, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do this before drainBody beause there's no need for the I/O if
|
// We do this before drainBody because there's no need for the I/O if
|
||||||
// we're breaking out
|
// we're breaking out
|
||||||
remain := c.RetryMax - i
|
remain := c.RetryMax - i
|
||||||
if remain <= 0 {
|
if remain <= 0 {
|
||||||
@ -450,7 +655,7 @@ func (c *Client) Do(req *Request) (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We're going to retry, consume any response to reuse the connection.
|
// We're going to retry, consume any response to reuse the connection.
|
||||||
if err == nil && resp != nil {
|
if doErr == nil {
|
||||||
c.drainBody(resp.Body)
|
c.drainBody(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,27 +664,58 @@ func (c *Client) Do(req *Request) (*http.Response, error) {
|
|||||||
if code > 0 {
|
if code > 0 {
|
||||||
desc = fmt.Sprintf("%s (status: %d)", desc, code)
|
desc = fmt.Sprintf("%s (status: %d)", desc, code)
|
||||||
}
|
}
|
||||||
if c.Logger != nil {
|
if logger != nil {
|
||||||
c.Logger.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain)
|
switch v := logger.(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case <-req.Context().Done():
|
case <-req.Context().Done():
|
||||||
|
c.HTTPClient.CloseIdleConnections()
|
||||||
return nil, req.Context().Err()
|
return nil, req.Context().Err()
|
||||||
case <-time.After(wait):
|
case <-time.After(wait):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make shallow copy of http Request so that we can modify its body
|
||||||
|
// without racing against the closeBody call in persistConn.writeLoop.
|
||||||
|
httpreq := *req.Request
|
||||||
|
req.Request = &httpreq
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the closest we have to success criteria
|
||||||
|
if doErr == nil && checkErr == nil && !shouldRetry {
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer c.HTTPClient.CloseIdleConnections()
|
||||||
|
|
||||||
|
err := doErr
|
||||||
|
if checkErr != nil {
|
||||||
|
err = checkErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ErrorHandler != nil {
|
if c.ErrorHandler != nil {
|
||||||
return c.ErrorHandler(resp, err, c.RetryMax+1)
|
return c.ErrorHandler(resp, err, attempt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, we close the response body and return an error without
|
// By default, we close the response body and return an error without
|
||||||
// returning the response
|
// returning the response
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
resp.Body.Close()
|
c.drainBody(resp.Body)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("%s %s giving up after %d attempts",
|
|
||||||
req.Method, req.URL, c.RetryMax+1)
|
// this means CheckRetry thought the request was a failure, but didn't
|
||||||
|
// communicate why
|
||||||
|
if err == nil {
|
||||||
|
return nil, fmt.Errorf("%s %s giving up after %d attempt(s)",
|
||||||
|
req.Method, req.URL, attempt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("%s %s giving up after %d attempt(s): %w",
|
||||||
|
req.Method, req.URL, attempt, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to read the response body so we can reuse this connection.
|
// Try to read the response body so we can reuse this connection.
|
||||||
@ -487,8 +723,13 @@ func (c *Client) drainBody(body io.ReadCloser) {
|
|||||||
defer body.Close()
|
defer body.Close()
|
||||||
_, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit))
|
_, err := io.Copy(ioutil.Discard, io.LimitReader(body, respReadLimit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if c.Logger != nil {
|
if c.logger() != nil {
|
||||||
c.Logger.Printf("[ERR] error reading response body: %v", err)
|
switch v := c.logger().(type) {
|
||||||
|
case LeveledLogger:
|
||||||
|
v.Error("error reading response body", "error", err)
|
||||||
|
case Logger:
|
||||||
|
v.Printf("[ERR] error reading response body: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -547,3 +788,11 @@ func PostForm(url string, data url.Values) (*http.Response, error) {
|
|||||||
func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
|
func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) {
|
||||||
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StandardClient returns a stdlib *http.Client with a custom Transport, which
|
||||||
|
// shims in a *retryablehttp.Client for added retries.
|
||||||
|
func (c *Client) StandardClient() *http.Client {
|
||||||
|
return &http.Client{
|
||||||
|
Transport: &RoundTripper{Client: c},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
7
vendor/github.com/hashicorp/go-retryablehttp/go.mod
generated
vendored
7
vendor/github.com/hashicorp/go-retryablehttp/go.mod
generated
vendored
@ -1,3 +1,8 @@
|
|||||||
module github.com/hashicorp/go-retryablehttp
|
module github.com/hashicorp/go-retryablehttp
|
||||||
|
|
||||||
require github.com/hashicorp/go-cleanhttp v0.5.0
|
require (
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2
|
||||||
|
)
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
12
vendor/github.com/hashicorp/go-retryablehttp/go.sum
generated
vendored
12
vendor/github.com/hashicorp/go-retryablehttp/go.sum
generated
vendored
@ -1,2 +1,10 @@
|
|||||||
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
52
vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go
generated
vendored
Normal file
52
vendor/github.com/hashicorp/go-retryablehttp/roundtripper.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package retryablehttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoundTripper implements the http.RoundTripper interface, using a retrying
|
||||||
|
// HTTP client to execute requests.
|
||||||
|
//
|
||||||
|
// It is important to note that retryablehttp doesn't always act exactly as a
|
||||||
|
// RoundTripper should. This is highly dependent on the retryable client's
|
||||||
|
// configuration.
|
||||||
|
type RoundTripper struct {
|
||||||
|
// The client to use during requests. If nil, the default retryablehttp
|
||||||
|
// client and settings will be used.
|
||||||
|
Client *Client
|
||||||
|
|
||||||
|
// once ensures that the logic to initialize the default client runs at
|
||||||
|
// most once, in a single thread.
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes the underlying retryable client.
|
||||||
|
func (rt *RoundTripper) init() {
|
||||||
|
if rt.Client == nil {
|
||||||
|
rt.Client = NewClient()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundTrip satisfies the http.RoundTripper interface.
|
||||||
|
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
rt.once.Do(rt.init)
|
||||||
|
|
||||||
|
// Convert the request to be retryable.
|
||||||
|
retryableReq, err := FromRequest(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the request.
|
||||||
|
resp, err := rt.Client.Do(retryableReq)
|
||||||
|
// If we got an error returned by standard library's `Do` method, unwrap it
|
||||||
|
// otherwise we will wind up erroneously re-nesting the error.
|
||||||
|
if _, ok := err.(*url.Error); ok {
|
||||||
|
return resp, errors.Unwrap(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, err
|
||||||
|
}
|
20
vendor/github.com/hashicorp/vault/api/auth_token.go
generated
vendored
20
vendor/github.com/hashicorp/vault/api/auth_token.go
generated
vendored
@ -115,6 +115,26 @@ func (c *TokenAuth) LookupSelf() (*Secret, error) {
|
|||||||
return ParseSecret(resp.Body)
|
return ParseSecret(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *TokenAuth) RenewAccessor(accessor string, increment int) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("POST", "/v1/auth/token/renew-accessor")
|
||||||
|
if err := r.SetJSONBody(map[string]interface{}{
|
||||||
|
"accessor": accessor,
|
||||||
|
"increment": increment,
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
defer cancelFunc()
|
||||||
|
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return ParseSecret(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) {
|
func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) {
|
||||||
r := c.c.NewRequest("PUT", "/v1/auth/token/renew")
|
r := c.c.NewRequest("PUT", "/v1/auth/token/renew")
|
||||||
if err := r.SetJSONBody(map[string]interface{}{
|
if err := r.SetJSONBody(map[string]interface{}{
|
||||||
|
82
vendor/github.com/hashicorp/vault/api/client.go
generated
vendored
82
vendor/github.com/hashicorp/vault/api/client.go
generated
vendored
@ -32,6 +32,7 @@ const EnvVaultCAPath = "VAULT_CAPATH"
|
|||||||
const EnvVaultClientCert = "VAULT_CLIENT_CERT"
|
const EnvVaultClientCert = "VAULT_CLIENT_CERT"
|
||||||
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
||||||
const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
|
const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
|
||||||
|
const EnvVaultSRVLookup = "VAULT_SRV_LOOKUP"
|
||||||
const EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
|
const EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
|
||||||
const EnvVaultNamespace = "VAULT_NAMESPACE"
|
const EnvVaultNamespace = "VAULT_NAMESPACE"
|
||||||
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
|
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
|
||||||
@ -49,7 +50,8 @@ const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
|
|||||||
// returns an optional string duration to be used for response wrapping (e.g.
|
// returns an optional string duration to be used for response wrapping (e.g.
|
||||||
// "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/",
|
// "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/",
|
||||||
// however, end-of-path forward slashes are not trimmed, so must match your
|
// however, end-of-path forward slashes are not trimmed, so must match your
|
||||||
// called path precisely.
|
// called path precisely. Response wrapping will only be used when the return
|
||||||
|
// value is not the empty string.
|
||||||
type WrappingLookupFunc func(operation, path string) string
|
type WrappingLookupFunc func(operation, path string) string
|
||||||
|
|
||||||
// Config is used to configure the creation of the client.
|
// Config is used to configure the creation of the client.
|
||||||
@ -88,6 +90,9 @@ type Config struct {
|
|||||||
// The Backoff function to use; a default is used if not provided
|
// The Backoff function to use; a default is used if not provided
|
||||||
Backoff retryablehttp.Backoff
|
Backoff retryablehttp.Backoff
|
||||||
|
|
||||||
|
// The CheckRetry function to use; a default is used if not provided
|
||||||
|
CheckRetry retryablehttp.CheckRetry
|
||||||
|
|
||||||
// Limiter is the rate limiter used by the client.
|
// Limiter is the rate limiter used by the client.
|
||||||
// If this pointer is nil, then there will be no limit set.
|
// If this pointer is nil, then there will be no limit set.
|
||||||
// In contrast, if this pointer is set, even to an empty struct,
|
// In contrast, if this pointer is set, even to an empty struct,
|
||||||
@ -102,6 +107,9 @@ type Config struct {
|
|||||||
// Note: It is not thread-safe to set this and make concurrent requests
|
// Note: It is not thread-safe to set this and make concurrent requests
|
||||||
// with the same client. Cloning a client will not clone this value.
|
// with the same client. Cloning a client will not clone this value.
|
||||||
OutputCurlString bool
|
OutputCurlString bool
|
||||||
|
|
||||||
|
// SRVLookup enables the client to lookup the host through DNS SRV lookup
|
||||||
|
SRVLookup bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLSConfig contains the parameters needed to configure TLS on the HTTP client
|
// TLSConfig contains the parameters needed to configure TLS on the HTTP client
|
||||||
@ -140,8 +148,8 @@ func DefaultConfig() *Config {
|
|||||||
config := &Config{
|
config := &Config{
|
||||||
Address: "https://127.0.0.1:8200",
|
Address: "https://127.0.0.1:8200",
|
||||||
HttpClient: cleanhttp.DefaultPooledClient(),
|
HttpClient: cleanhttp.DefaultPooledClient(),
|
||||||
|
Timeout: time.Second * 60,
|
||||||
}
|
}
|
||||||
config.HttpClient.Timeout = time.Second * 60
|
|
||||||
|
|
||||||
transport := config.HttpClient.Transport.(*http.Transport)
|
transport := config.HttpClient.Transport.(*http.Transport)
|
||||||
transport.TLSHandshakeTimeout = 10 * time.Second
|
transport.TLSHandshakeTimeout = 10 * time.Second
|
||||||
@ -242,6 +250,7 @@ func (c *Config) ReadEnvironment() error {
|
|||||||
var envInsecure bool
|
var envInsecure bool
|
||||||
var envTLSServerName string
|
var envTLSServerName string
|
||||||
var envMaxRetries *uint64
|
var envMaxRetries *uint64
|
||||||
|
var envSRVLookup bool
|
||||||
var limit *rate.Limiter
|
var limit *rate.Limiter
|
||||||
|
|
||||||
// Parse the environment variables
|
// Parse the environment variables
|
||||||
@ -299,6 +308,13 @@ func (c *Config) ReadEnvironment() error {
|
|||||||
return fmt.Errorf("could not parse VAULT_INSECURE")
|
return fmt.Errorf("could not parse VAULT_INSECURE")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if v := os.Getenv(EnvVaultSRVLookup); v != "" {
|
||||||
|
var err error
|
||||||
|
envSRVLookup, err = strconv.ParseBool(v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not parse %s", EnvVaultSRVLookup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if v := os.Getenv(EnvVaultTLSServerName); v != "" {
|
if v := os.Getenv(EnvVaultTLSServerName); v != "" {
|
||||||
envTLSServerName = v
|
envTLSServerName = v
|
||||||
@ -317,6 +333,7 @@ func (c *Config) ReadEnvironment() error {
|
|||||||
c.modifyLock.Lock()
|
c.modifyLock.Lock()
|
||||||
defer c.modifyLock.Unlock()
|
defer c.modifyLock.Unlock()
|
||||||
|
|
||||||
|
c.SRVLookup = envSRVLookup
|
||||||
c.Limiter = limit
|
c.Limiter = limit
|
||||||
|
|
||||||
if err := c.ConfigureTLS(t); err != nil {
|
if err := c.ConfigureTLS(t); err != nil {
|
||||||
@ -427,10 +444,14 @@ func NewClient(c *Config) (*Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
client := &Client{
|
client := &Client{
|
||||||
addr: u,
|
addr: u,
|
||||||
config: c,
|
config: c,
|
||||||
|
headers: make(http.Header),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the VaultRequest SSRF protection header
|
||||||
|
client.headers[consts.RequestHeaderName] = []string{"true"}
|
||||||
|
|
||||||
if token := os.Getenv(EnvVaultToken); token != "" {
|
if token := os.Getenv(EnvVaultToken); token != "" {
|
||||||
client.token = token
|
client.token = token
|
||||||
}
|
}
|
||||||
@ -488,6 +509,16 @@ func (c *Client) SetMaxRetries(retries int) {
|
|||||||
c.config.MaxRetries = retries
|
c.config.MaxRetries = retries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCheckRetry sets the CheckRetry function to be used for future requests.
|
||||||
|
func (c *Client) SetCheckRetry(checkRetry retryablehttp.CheckRetry) {
|
||||||
|
c.modifyLock.RLock()
|
||||||
|
c.config.modifyLock.Lock()
|
||||||
|
defer c.config.modifyLock.Unlock()
|
||||||
|
c.modifyLock.RUnlock()
|
||||||
|
|
||||||
|
c.config.CheckRetry = checkRetry
|
||||||
|
}
|
||||||
|
|
||||||
// SetClientTimeout sets the client request timeout
|
// SetClientTimeout sets the client request timeout
|
||||||
func (c *Client) SetClientTimeout(timeout time.Duration) {
|
func (c *Client) SetClientTimeout(timeout time.Duration) {
|
||||||
c.modifyLock.RLock()
|
c.modifyLock.RLock()
|
||||||
@ -517,7 +548,7 @@ func (c *Client) SetOutputCurlString(curl bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
|
// CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
|
||||||
// for a given operation and path
|
// for a given operation and path.
|
||||||
func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
|
func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
|
||||||
c.modifyLock.RLock()
|
c.modifyLock.RLock()
|
||||||
defer c.modifyLock.RUnlock()
|
defer c.modifyLock.RUnlock()
|
||||||
@ -526,7 +557,7 @@ func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
|
// SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
|
||||||
// for a given operation and path
|
// for a given operation and path.
|
||||||
func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
|
func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
|
||||||
c.modifyLock.Lock()
|
c.modifyLock.Lock()
|
||||||
defer c.modifyLock.Unlock()
|
defer c.modifyLock.Unlock()
|
||||||
@ -586,7 +617,7 @@ func (c *Client) ClearToken() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Headers gets the current set of headers used for requests. This returns a
|
// Headers gets the current set of headers used for requests. This returns a
|
||||||
// copy; to modify it make modifications locally and use SetHeaders.
|
// copy; to modify it call AddHeader or SetHeaders.
|
||||||
func (c *Client) Headers() http.Header {
|
func (c *Client) Headers() http.Header {
|
||||||
c.modifyLock.RLock()
|
c.modifyLock.RLock()
|
||||||
defer c.modifyLock.RUnlock()
|
defer c.modifyLock.RUnlock()
|
||||||
@ -605,11 +636,19 @@ func (c *Client) Headers() http.Header {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHeaders sets the headers to be used for future requests.
|
// AddHeader allows a single header key/value pair to be added
|
||||||
|
// in a race-safe fashion.
|
||||||
|
func (c *Client) AddHeader(key, value string) {
|
||||||
|
c.modifyLock.Lock()
|
||||||
|
defer c.modifyLock.Unlock()
|
||||||
|
c.headers.Add(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHeaders clears all previous headers and uses only the given
|
||||||
|
// ones going forward.
|
||||||
func (c *Client) SetHeaders(headers http.Header) {
|
func (c *Client) SetHeaders(headers http.Header) {
|
||||||
c.modifyLock.Lock()
|
c.modifyLock.Lock()
|
||||||
defer c.modifyLock.Unlock()
|
defer c.modifyLock.Unlock()
|
||||||
|
|
||||||
c.headers = headers
|
c.headers = headers
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,6 +682,7 @@ func (c *Client) Clone() (*Client, error) {
|
|||||||
MaxRetries: config.MaxRetries,
|
MaxRetries: config.MaxRetries,
|
||||||
Timeout: config.Timeout,
|
Timeout: config.Timeout,
|
||||||
Backoff: config.Backoff,
|
Backoff: config.Backoff,
|
||||||
|
CheckRetry: config.CheckRetry,
|
||||||
Limiter: config.Limiter,
|
Limiter: config.Limiter,
|
||||||
}
|
}
|
||||||
config.modifyLock.RUnlock()
|
config.modifyLock.RUnlock()
|
||||||
@ -669,15 +709,14 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
|
|||||||
token := c.token
|
token := c.token
|
||||||
mfaCreds := c.mfaCreds
|
mfaCreds := c.mfaCreds
|
||||||
wrappingLookupFunc := c.wrappingLookupFunc
|
wrappingLookupFunc := c.wrappingLookupFunc
|
||||||
headers := c.headers
|
|
||||||
policyOverride := c.policyOverride
|
policyOverride := c.policyOverride
|
||||||
c.modifyLock.RUnlock()
|
c.modifyLock.RUnlock()
|
||||||
|
|
||||||
|
var host = addr.Host
|
||||||
// if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV
|
// if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV
|
||||||
// record and take the highest match; this is not designed for high-availability, just discovery
|
// record and take the highest match; this is not designed for high-availability, just discovery
|
||||||
var host string = addr.Host
|
// Internet Draft specifies that the SRV record is ignored if a port is given
|
||||||
if addr.Port() == "" {
|
if addr.Port() == "" && c.config.SRVLookup {
|
||||||
// Internet Draft specifies that the SRV record is ignored if a port is given
|
|
||||||
_, addrs, err := net.LookupSRV("http", "tcp", addr.Hostname())
|
_, addrs, err := net.LookupSRV("http", "tcp", addr.Hostname())
|
||||||
if err == nil && len(addrs) > 0 {
|
if err == nil && len(addrs) > 0 {
|
||||||
host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port)
|
host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port)
|
||||||
@ -692,6 +731,7 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
|
|||||||
Host: host,
|
Host: host,
|
||||||
Path: path.Join(addr.Path, requestPath),
|
Path: path.Join(addr.Path, requestPath),
|
||||||
},
|
},
|
||||||
|
Host: addr.Host,
|
||||||
ClientToken: token,
|
ClientToken: token,
|
||||||
Params: make(map[string][]string),
|
Params: make(map[string][]string),
|
||||||
}
|
}
|
||||||
@ -714,10 +754,7 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
|
|||||||
req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath)
|
req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if headers != nil {
|
req.Headers = c.Headers()
|
||||||
req.Headers = headers
|
|
||||||
}
|
|
||||||
|
|
||||||
req.PolicyOverride = policyOverride
|
req.PolicyOverride = policyOverride
|
||||||
|
|
||||||
return req
|
return req
|
||||||
@ -740,6 +777,7 @@ func (c *Client) RawRequestWithContext(ctx context.Context, r *Request) (*Respon
|
|||||||
c.config.modifyLock.RLock()
|
c.config.modifyLock.RLock()
|
||||||
limiter := c.config.Limiter
|
limiter := c.config.Limiter
|
||||||
maxRetries := c.config.MaxRetries
|
maxRetries := c.config.MaxRetries
|
||||||
|
checkRetry := c.config.CheckRetry
|
||||||
backoff := c.config.Backoff
|
backoff := c.config.Backoff
|
||||||
httpClient := c.config.HttpClient
|
httpClient := c.config.HttpClient
|
||||||
timeout := c.config.Timeout
|
timeout := c.config.Timeout
|
||||||
@ -776,6 +814,10 @@ START:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if timeout != 0 {
|
if timeout != 0 {
|
||||||
|
// Note: we purposefully do not call cancel manually. The reason is
|
||||||
|
// when canceled, the request.Body will EOF when reading due to the way
|
||||||
|
// it streams data in. Cancel will still be run when the timeout is
|
||||||
|
// hit, so this doesn't really harm anything.
|
||||||
ctx, _ = context.WithTimeout(ctx, timeout)
|
ctx, _ = context.WithTimeout(ctx, timeout)
|
||||||
}
|
}
|
||||||
req.Request = req.Request.WithContext(ctx)
|
req.Request = req.Request.WithContext(ctx)
|
||||||
@ -784,13 +826,17 @@ START:
|
|||||||
backoff = retryablehttp.LinearJitterBackoff
|
backoff = retryablehttp.LinearJitterBackoff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if checkRetry == nil {
|
||||||
|
checkRetry = retryablehttp.DefaultRetryPolicy
|
||||||
|
}
|
||||||
|
|
||||||
client := &retryablehttp.Client{
|
client := &retryablehttp.Client{
|
||||||
HTTPClient: httpClient,
|
HTTPClient: httpClient,
|
||||||
RetryWaitMin: 1000 * time.Millisecond,
|
RetryWaitMin: 1000 * time.Millisecond,
|
||||||
RetryWaitMax: 1500 * time.Millisecond,
|
RetryWaitMax: 1500 * time.Millisecond,
|
||||||
RetryMax: maxRetries,
|
RetryMax: maxRetries,
|
||||||
CheckRetry: retryablehttp.DefaultRetryPolicy,
|
|
||||||
Backoff: backoff,
|
Backoff: backoff,
|
||||||
|
CheckRetry: checkRetry,
|
||||||
ErrorHandler: retryablehttp.PassthroughErrorHandler,
|
ErrorHandler: retryablehttp.PassthroughErrorHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
vendor/github.com/hashicorp/vault/api/go.mod
generated
vendored
19
vendor/github.com/hashicorp/vault/api/go.mod
generated
vendored
@ -1,19 +1,20 @@
|
|||||||
module github.com/hashicorp/vault/api
|
module github.com/hashicorp/vault/api
|
||||||
|
|
||||||
go 1.12
|
go 1.13
|
||||||
|
|
||||||
replace github.com/hashicorp/vault/sdk => ../sdk
|
replace github.com/hashicorp/vault/sdk => ../sdk
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/go-test/deep v1.0.2
|
||||||
github.com/hashicorp/errwrap v1.0.0
|
github.com/hashicorp/errwrap v1.0.0
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1
|
github.com/hashicorp/go-cleanhttp v0.5.1
|
||||||
github.com/hashicorp/go-multierror v1.0.0
|
github.com/hashicorp/go-multierror v1.1.0
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.4
|
github.com/hashicorp/go-retryablehttp v0.6.6
|
||||||
github.com/hashicorp/go-rootcerts v1.0.1
|
github.com/hashicorp/go-rootcerts v1.0.2
|
||||||
github.com/hashicorp/hcl v1.0.0
|
github.com/hashicorp/hcl v1.0.0
|
||||||
github.com/hashicorp/vault/sdk v0.1.13
|
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267
|
||||||
github.com/mitchellh/mapstructure v1.1.2
|
github.com/mitchellh/mapstructure v1.3.2
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1
|
gopkg.in/square/go-jose.v2 v2.5.1
|
||||||
)
|
)
|
||||||
|
603
vendor/github.com/hashicorp/vault/api/go.sum
generated
vendored
603
vendor/github.com/hashicorp/vault/api/go.sum
generated
vendored
@ -1,118 +1,711 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts=
|
||||||
|
code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:sk5LnIjB/nIEU7yP5sDQExVm62wu0pBh3yrElngUisI=
|
||||||
|
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||||
|
github.com/Azure/azure-sdk-for-go v36.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.6.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.7.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.4.0/go.mod h1:Oo5cRhLvZteXzI2itUm5ziqsoIxRkzrt3t61FeZaS18=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.3.0/go.mod h1:rNYMNAefZMRowqCV0cVhr/YDW5dD7afFq9nXAXL4ykE=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
|
||||||
|
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
|
github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
|
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
|
||||||
|
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
|
github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
|
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||||
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||||
|
github.com/SAP/go-hdb v0.14.1/go.mod h1:7fdQLVC2lER3urZLjZCm0AuMQfApof92n3aylBPEkMo=
|
||||||
|
github.com/Sectorbob/mlab-ns2 v0.0.0-20171030222938-d3aa0c295a8a/go.mod h1:D73UAuEPckrDorYZdtlCu2ySOLuPB5W4rhIkmmc/XbI=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
|
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190412020505-60e2075261b6/go.mod h1:T9M45xf79ahXVelWoOBmH0y4aC1t5kXO5BxwyakgIGA=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190620160927-9418d7b0cd0f/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
|
||||||
|
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/apple/foundationdb/bindings/go v0.0.0-20190411004307-cd5c9d91fad2/go.mod h1:OMVSB21p9+xQUIqlGizHPZfjK+SHws1ht+ZytVDoz9U=
|
||||||
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
|
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
||||||
|
github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs=
|
||||||
|
github.com/armon/go-metrics v0.3.1/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||||
|
github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||||
|
github.com/armon/go-proxyproto v0.0.0-20190211145416-68259f75880e/go.mod h1:QmP9hvJ91BbJmGVGSbutW19IC0Q9phDCLGaomwTJbgU=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||||
|
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||||
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
|
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/briankassouf/jose v0.9.2-0.20180619214549-d2569464773f/go.mod h1:HQhVmdUf7dBNwIIdBTivnCDxcf6IZY3/zrb+uKSJz6Y=
|
||||||
|
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/centrify/cloud-golang-sdk v0.0.0-20190214225812-119110094d0f/go.mod h1:C0rtzmGXgN78pYR0tGJFhtHgkbAs0lIbHwkB81VxDQE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chrismalek/oktasdk-go v0.0.0-20181212195951-3430665dfaa0/go.mod h1:5d8DqS60xkj9k3aXfL3+mXBH0DPYO0FQjcKosxl+b/Q=
|
||||||
|
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||||
|
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381/go.mod h1:e5+USP2j8Le2M0Jo3qKPFnNhuo1wueU4nWHCXBOfQ14=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
|
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
|
||||||
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
|
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||||
|
github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||||
|
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||||
|
github.com/coreos/go-oidc v2.0.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
|
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/denisenkom/go-mssqldb v0.0.0-20190412130859-3b1d194e553a/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
|
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
github.com/docker/docker v1.4.2-0.20200319182547-c7ad2b866182/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
|
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
|
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||||
|
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||||
|
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||||
|
github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo=
|
||||||
|
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||||
|
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
|
github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
|
||||||
|
github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
|
||||||
|
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
|
||||||
|
github.com/gammazero/deque v0.0.0-20190130191400-2afb3858e9c7/go.mod h1:GeIq9qoE43YdGnDXURnmKTnGg15pQz4mYkXSTChbneI=
|
||||||
|
github.com/gammazero/workerpool v0.0.0-20190406235159-88d534f22b56/go.mod h1:w9RqFVO2BM3xwWEcAB8Fwp0OviTBBEiRmSBDfbXnd3w=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
|
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8=
|
||||||
|
github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
|
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||||
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31 h1:28FVBuwkwowZMjbA7M0wXsI6t3PYulRTMio3SO+eKCM=
|
||||||
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||||
|
github.com/gocql/gocql v0.0.0-20190402132108-0e1d5de854df/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
|
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
|
github.com/google/go-metrics-stackdriver v0.2.0/go.mod h1:KLcPyp3dWJAFD+yHisGlJSZktIsTjb50eB72U2YZ9K0=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=
|
||||||
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
|
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
|
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
|
github.com/hashicorp/consul-template v0.25.0/go.mod h1:/vUsrJvDuuQHcxEw0zik+YXTS7ZKWZjQeaQhshBmfH0=
|
||||||
|
github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU=
|
||||||
|
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||||
|
github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
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/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
github.com/hashicorp/go-gatedio v0.5.0/go.mod h1:Lr3t8L6IyxD3DAeaUxGcgl2JnRUpWMCsmBl4Omu/2t4=
|
||||||
|
github.com/hashicorp/go-gcp-common v0.5.0/go.mod h1:IDGUI2N/OS3PiU4qZcXJeWKPI6O/9Y8hOrbSiMcqyYw=
|
||||||
|
github.com/hashicorp/go-gcp-common v0.6.0/go.mod h1:RuZi18562/z30wxOzpjeRrGcmk9Ro/rBzixaSZDhIhY=
|
||||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||||
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.10.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
|
||||||
|
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
|
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||||
|
github.com/hashicorp/go-kms-wrapping v0.5.1/go.mod h1:cGIibZmMx9qlxS1pZTUrEgGqA+7u3zJyvVYMhjU2bDs=
|
||||||
|
github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g=
|
||||||
|
github.com/hashicorp/go-memdb v1.0.2/go.mod h1:I6dKdmYhZqU0RJSheVEWgTNWdVQH5QvTgIUQ0t/t32M=
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
|
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
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-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||||
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.4 h1:1BZvpawXoJCWX6pNtow9+rpEj+3itIlutiqnntI6jOE=
|
github.com/hashicorp/go-raftchunking v0.6.3-0.20191002164813-7e9e8525653a/go.mod h1:xbXnmKqX9/+RhPkJ4zrEx4738HacP72aaUPlT2RZ4sU=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.2 h1:bHM2aVXwBtBJWxHtkSrWuI4umABCUczs52eiUS9nSiw=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
|
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
|
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||||
|
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2-0.20191001231223-f32f5fe8d6a8/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
|
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||||
|
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
|
github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
|
github.com/hashicorp/nomad/api v0.0.0-20191220223628-edc62acd919d/go.mod h1:WKCL+tLVhN1D+APwH3JiTRZoxcdwRk86bWu1LVCUPaE=
|
||||||
|
github.com/hashicorp/raft v1.0.1/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI=
|
||||||
|
github.com/hashicorp/raft v1.1.2-0.20191002163536-9c6bd3e3eb17/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=
|
||||||
|
github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=
|
||||||
|
github.com/hashicorp/raft-snapshot v1.0.2-0.20190827162939-8117efcc5aab/go.mod h1:5sL9eUn72lH5DzsFIJ9jaysITbHksSSszImWSOTC8Ic=
|
||||||
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
|
github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
|
||||||
|
github.com/hashicorp/vault v1.4.2/go.mod h1:500fLOj7p92Ys4X265LizqF78MzmHJUf1jV1zNJt060=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-alicloud v0.5.5/go.mod h1:sQ+VNwPQlemgXHXikYH6onfH9gPwDZ1GUVRLz0ZvHx8=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-azure v0.5.6-0.20200422235613-1b5c70f9ef68/go.mod h1:RCVBsf8AJndh4c6iGZtvVZFui9SG0Bj9fnF0SodNIkw=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-centrify v0.5.5/go.mod h1:GfRoy7NHsuR/ogmZtbExdJXUwbfwcxPrS9xzkyy2J/c=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-cf v0.5.4/go.mod h1:idkFYHc6ske2BE7fe00SpH+SBIlqDKz8vk/IPLJuX2o=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-gcp v0.5.1/go.mod h1:eLj92eX8MPI4vY1jaazVLF2sVbSAJ3LRHLRhF/pUmlI=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-gcp v0.6.2-0.20200428223335-82bd3a3ad5b3/go.mod h1:U0fkAlxWTEyQ74lx8wlGdD493lP1DD/qpMjXgOEbwj0=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-jwt v0.6.2/go.mod h1:SFadxIfoLGzugEjwUUmUaCGbsYEz2/jJymZDDQjEqYg=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-kerberos v0.1.5/go.mod h1:r4UqWITHYKmBeAMKPWqLo4V8bl/wNqoSIaQcMpeK9ss=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-kubernetes v0.6.1/go.mod h1:/Y9W5aZULfPeNVRQK0/nrFGpHWyNm0J3UWhOdsAu0vM=
|
||||||
|
github.com/hashicorp/vault-plugin-auth-oci v0.5.4/go.mod h1:j05O2b9fw2Q82NxDPhHMYVfHKvitUYGWfmqmpBdqmmc=
|
||||||
|
github.com/hashicorp/vault-plugin-database-elasticsearch v0.5.4/go.mod h1:QjGrrxcRXv/4XkEZAlM0VMZEa3uxKAICFqDj27FP/48=
|
||||||
|
github.com/hashicorp/vault-plugin-database-mongodbatlas v0.1.2-0.20200520204052-f840e9d4895c/go.mod h1:MP3kfr0N+7miOTZFwKv952b9VkXM4S2Q6YtQCiNKWq8=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-ad v0.6.6-0.20200520202259-fc6b89630f9f/go.mod h1:kk98nB+cwDbt3I7UGQq3ota7+eHZrGSTQZfSRGpluvA=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-alicloud v0.5.5/go.mod h1:gAoReoUpBHaBwkxQqTK7FY8nQC0MuaZHLiW5WOSny5g=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-azure v0.5.6/go.mod h1:Q0cIL4kZWnMmQWkBfWtyOd7+JXTEpAyU4L932PMHq3E=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-gcp v0.6.2-0.20200507171538-2548e2b5058d/go.mod h1:jVTE1fuhRcBOb/gnCT9W++AnlwiyQEX4S8iVCKhKQsE=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-gcpkms v0.5.5/go.mod h1:b6RwFD1bny1zbfqhD35iGJdQYHRtJLx3HfBD109GO38=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-kv v0.5.5/go.mod h1:oNyUoMMQq6uNTwyYPnkldiedaknYbPfQIdKoyKQdy2g=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-mongodbatlas v0.1.2/go.mod h1:YRW9zn9NZNitRlPYNAWRp/YEdKCF/X8aOg8IYSxFT5Y=
|
||||||
|
github.com/hashicorp/vault-plugin-secrets-openldap v0.1.3-0.20200518214608-746aba5fead6/go.mod h1:9Cy4Jp779BjuIOhYLjEfH3M3QCUxZgPnvJ3tAOOmof4=
|
||||||
|
github.com/hashicorp/vault/api v1.0.1/go.mod h1:AV/+M5VPDpB90arloVX0rVDUIHkONiwz5Uza9HRtpUE=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20190730042357-746c0b111519/go.mod h1:i9PKqwFko/s/aihU1uuHGh/FaQS+Xcgvd9dvnfAvQb0=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20191122173911-80fcc7907c78/go.mod h1:Uf8LaHyrYsgVgHzO2tMZKhqRGlL3UJ6XaSwW2EA1Iqo=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20200215224050-f6547fa8e820/go.mod h1:3f12BMfgDGjTsTtIUj+ZKZwSobQpZtYGFIEehOv5z1o=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20200317185738-82f498082f02/go.mod h1:3f12BMfgDGjTsTtIUj+ZKZwSobQpZtYGFIEehOv5z1o=
|
||||||
|
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE=
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/influxdata/influxdb v0.0.0-20190411212539-d24b7ba8c4c4/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||||
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||||
|
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
|
github.com/jcmturner/aescts v1.0.1/go.mod h1:k9gJoDUf1GH5r2IBtBjwjDCoLELYxOcEhitdP8RL7qQ=
|
||||||
|
github.com/jcmturner/dnsutils v1.0.1/go.mod h1:tqMo38L01jO8AKxT0S9OQVlGZu3dkEt+z5CA+LOhwB0=
|
||||||
|
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||||
|
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.0.0/go.mod h1:4/sqKY8Yzo/TIQ8MoCyk/EPcjb+czI9czxHcdXuZbFA=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
|
github.com/jeffchao/backoff v0.0.0-20140404060208-9d7fd7aa17f2/go.mod h1:xkfESuHriIekR+4RoV+fu91j/CfnYM29Zi2tMFw5iD4=
|
||||||
|
github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f/go.mod h1:3J2qVK16Lq8V+wfiL2lPeDZ7UWMxk5LemerHa1p6N00=
|
||||||
|
github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/joyent/triton-go v0.0.0-20190112182421-51ffac552869/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA=
|
||||||
|
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||||
|
github.com/keybase/go-crypto v0.0.0-20190403132359-d65b6b94177f/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/martini-contrib/render v0.0.0-20150707142108-ec18f8345a11/go.mod h1:Ah2dBMoxZEqk118as2T4u4fjfXarE0pPnMJaArZQZsI=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
|
||||||
|
github.com/michaelklishin/rabbit-hole v0.0.0-20191008194146-93d9988f0cd5/go.mod h1:+pmbihVqjC3GPdfWv1V2TnRSuVvwrWLKfEP/MZVB/Wc=
|
||||||
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
|
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
|
github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
|
||||||
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
|
||||||
|
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/mitchellh/pointerstructure v0.0.0-20190430161007-f252a8fd71c8/go.mod h1:k4XwG94++jLVsSiTxo7qdIfXA9pj9EAeo0QsNNJOLZ8=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mongodb/go-client-mongodb-atlas v0.1.2/go.mod h1:LS8O0YLkA+sbtOb3fZLF10yY3tJM+1xATXMJ3oU35LU=
|
||||||
|
github.com/mwielbut/pointy v1.1.0/go.mod h1:MvvO+uMFj9T5DMda33HlvogsFBX7pWWKAkFIn4teYwY=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
|
github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY=
|
||||||
|
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||||
|
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||||
|
github.com/okta/okta-sdk-golang v1.0.1/go.mod h1:8k//sN2mFTq8Ayo90DqGbcumCkSmYjF0+2zkIbZysec=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||||
|
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
|
github.com/oracle/oci-go-sdk v12.5.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
|
github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
||||||
|
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
||||||
|
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0=
|
||||||
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/patrickmn/go-cache v0.0.0-20180815053127-5633e0862627/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pierrec/lz4 v2.2.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E=
|
||||||
|
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||||
|
github.com/pquerna/otp v1.2.1-0.20191009055518-468c2dd2b58d/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
|
github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
|
||||||
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
|
github.com/shirou/gopsutil v2.19.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
|
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||||
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180725160413-e900ae048470/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
|
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||||
|
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||||
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.etcd.io/etcd v0.5.0-alpha.5.0.20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
|
||||||
|
go.mongodb.org/mongo-driver v1.2.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||||
|
go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
|
||||||
|
go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
|
||||||
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk=
|
||||||
|
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||||
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190130055435-99b60b757ec1/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190718200317-82a3ea8a504c/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
|
google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU=
|
||||||
|
google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw=
|
||||||
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
|
google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190513181449-d00d292a067c/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
|
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||||
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
|
||||||
|
gopkg.in/ldap.v3 v3.0.3/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
|
gopkg.in/ory-am/dockertest.v3 v3.3.4/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
||||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
k8s.io/api v0.0.0-20190409092523-d687e77c8ae9/go.mod h1:FQEUn50aaytlU65qqBn/w+5ugllHwrBzKm7DzbnXdzE=
|
||||||
|
k8s.io/apimachinery v0.0.0-20190409092423-760d1845f48b/go.mod h1:FW86P8YXVLsbuplGMZeb20J3jYHscrDqw4jELaFJvRU=
|
||||||
|
k8s.io/klog v0.0.0-20190306015804-8e90cee79f82/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||||
|
layeh.com/radius v0.0.0-20190322222518-890bc1058917/go.mod h1:fywZKyu//X7iRzaxLgPWsvc0L26IUpVvE/aeIL2JtIQ=
|
||||||
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
|
384
vendor/github.com/hashicorp/vault/api/lifetime_watcher.go
generated
vendored
Normal file
384
vendor/github.com/hashicorp/vault/api/lifetime_watcher.go
generated
vendored
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrLifetimeWatcherMissingInput = errors.New("missing input")
|
||||||
|
ErrLifetimeWatcherMissingSecret = errors.New("missing secret")
|
||||||
|
ErrLifetimeWatcherNotRenewable = errors.New("secret is not renewable")
|
||||||
|
ErrLifetimeWatcherNoSecretData = errors.New("returned empty secret data")
|
||||||
|
|
||||||
|
// Deprecated; kept for compatibility
|
||||||
|
ErrRenewerMissingInput = errors.New("missing input to renewer")
|
||||||
|
ErrRenewerMissingSecret = errors.New("missing secret to renew")
|
||||||
|
ErrRenewerNotRenewable = errors.New("secret is not renewable")
|
||||||
|
ErrRenewerNoSecretData = errors.New("returned empty secret data")
|
||||||
|
|
||||||
|
// DefaultLifetimeWatcherRenewBuffer is the default size of the buffer for renew
|
||||||
|
// messages on the channel.
|
||||||
|
DefaultLifetimeWatcherRenewBuffer = 5
|
||||||
|
// Deprecated: kept for backwards compatibility
|
||||||
|
DefaultRenewerRenewBuffer = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
type RenewBehavior uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RenewBehaviorIgnoreErrors means we will attempt to keep renewing until
|
||||||
|
// we hit the lifetime threshold. It also ignores errors stemming from
|
||||||
|
// passing a non-renewable lease in. In practice, this means you simply
|
||||||
|
// reauthenticate/refetch credentials when the watcher exits. This is the
|
||||||
|
// default.
|
||||||
|
RenewBehaviorIgnoreErrors RenewBehavior = iota
|
||||||
|
|
||||||
|
// RenewBehaviorRenewDisabled turns off renewal attempts entirely. This
|
||||||
|
// allows you to simply watch lifetime and have the watcher return at a
|
||||||
|
// reasonable threshold without actually making Vault calls.
|
||||||
|
RenewBehaviorRenewDisabled
|
||||||
|
|
||||||
|
// RenewBehaviorErrorOnErrors is the "legacy" behavior which always exits
|
||||||
|
// on some kind of error
|
||||||
|
RenewBehaviorErrorOnErrors
|
||||||
|
)
|
||||||
|
|
||||||
|
// LifetimeWatcher is a process for watching lifetime of a secret.
|
||||||
|
//
|
||||||
|
// watcher, err := client.NewLifetimeWatcher(&LifetimeWatcherInput{
|
||||||
|
// Secret: mySecret,
|
||||||
|
// })
|
||||||
|
// go watcher.Start()
|
||||||
|
// defer watcher.Stop()
|
||||||
|
//
|
||||||
|
// for {
|
||||||
|
// select {
|
||||||
|
// case err := <-watcher.DoneCh():
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Renewal is now over
|
||||||
|
// case renewal := <-watcher.RenewCh():
|
||||||
|
// log.Printf("Successfully renewed: %#v", renewal)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// `DoneCh` will return if renewal fails, or if the remaining lease duration is
|
||||||
|
// under a built-in threshold and either renewing is not extending it or
|
||||||
|
// renewing is disabled. In both cases, the caller should attempt a re-read of
|
||||||
|
// the secret. Clients should check the return value of the channel to see if
|
||||||
|
// renewal was successful.
|
||||||
|
type LifetimeWatcher struct {
|
||||||
|
l sync.Mutex
|
||||||
|
|
||||||
|
client *Client
|
||||||
|
secret *Secret
|
||||||
|
grace time.Duration
|
||||||
|
random *rand.Rand
|
||||||
|
increment int
|
||||||
|
doneCh chan error
|
||||||
|
renewCh chan *RenewOutput
|
||||||
|
renewBehavior RenewBehavior
|
||||||
|
|
||||||
|
stopped bool
|
||||||
|
stopCh chan struct{}
|
||||||
|
|
||||||
|
errLifetimeWatcherNotRenewable error
|
||||||
|
errLifetimeWatcherNoSecretData error
|
||||||
|
}
|
||||||
|
|
||||||
|
// LifetimeWatcherInput is used as input to the renew function.
|
||||||
|
type LifetimeWatcherInput struct {
|
||||||
|
// Secret is the secret to renew
|
||||||
|
Secret *Secret
|
||||||
|
|
||||||
|
// DEPRECATED: this does not do anything.
|
||||||
|
Grace time.Duration
|
||||||
|
|
||||||
|
// Rand is the randomizer to use for underlying randomization. If not
|
||||||
|
// provided, one will be generated and seeded automatically. If provided, it
|
||||||
|
// is assumed to have already been seeded.
|
||||||
|
Rand *rand.Rand
|
||||||
|
|
||||||
|
// RenewBuffer is the size of the buffered channel where renew messages are
|
||||||
|
// dispatched.
|
||||||
|
RenewBuffer int
|
||||||
|
|
||||||
|
// The new TTL, in seconds, that should be set on the lease. The TTL set
|
||||||
|
// here may or may not be honored by the vault server, based on Vault
|
||||||
|
// configuration or any associated max TTL values.
|
||||||
|
Increment int
|
||||||
|
|
||||||
|
// RenewBehavior controls what happens when a renewal errors or the
|
||||||
|
// passed-in secret is not renewable.
|
||||||
|
RenewBehavior RenewBehavior
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenewOutput is the metadata returned to the client (if it's listening) to
|
||||||
|
// renew messages.
|
||||||
|
type RenewOutput struct {
|
||||||
|
// RenewedAt is the timestamp when the renewal took place (UTC).
|
||||||
|
RenewedAt time.Time
|
||||||
|
|
||||||
|
// Secret is the underlying renewal data. It's the same struct as all data
|
||||||
|
// that is returned from Vault, but since this is renewal data, it will not
|
||||||
|
// usually include the secret itself.
|
||||||
|
Secret *Secret
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLifetimeWatcher creates a new renewer from the given input.
|
||||||
|
func (c *Client) NewLifetimeWatcher(i *LifetimeWatcherInput) (*LifetimeWatcher, error) {
|
||||||
|
if i == nil {
|
||||||
|
return nil, ErrLifetimeWatcherMissingInput
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := i.Secret
|
||||||
|
if secret == nil {
|
||||||
|
return nil, ErrLifetimeWatcherMissingSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
random := i.Rand
|
||||||
|
if random == nil {
|
||||||
|
random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||||
|
}
|
||||||
|
|
||||||
|
renewBuffer := i.RenewBuffer
|
||||||
|
if renewBuffer == 0 {
|
||||||
|
renewBuffer = DefaultLifetimeWatcherRenewBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
return &LifetimeWatcher{
|
||||||
|
client: c,
|
||||||
|
secret: secret,
|
||||||
|
increment: i.Increment,
|
||||||
|
random: random,
|
||||||
|
doneCh: make(chan error, 1),
|
||||||
|
renewCh: make(chan *RenewOutput, renewBuffer),
|
||||||
|
renewBehavior: i.RenewBehavior,
|
||||||
|
|
||||||
|
stopped: false,
|
||||||
|
stopCh: make(chan struct{}),
|
||||||
|
|
||||||
|
errLifetimeWatcherNotRenewable: ErrLifetimeWatcherNotRenewable,
|
||||||
|
errLifetimeWatcherNoSecretData: ErrLifetimeWatcherNoSecretData,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: exists only for backwards compatibility. Calls
|
||||||
|
// NewLifetimeWatcher, and sets compatibility flags.
|
||||||
|
func (c *Client) NewRenewer(i *LifetimeWatcherInput) (*LifetimeWatcher, error) {
|
||||||
|
if i == nil {
|
||||||
|
return nil, ErrRenewerMissingInput
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := i.Secret
|
||||||
|
if secret == nil {
|
||||||
|
return nil, ErrRenewerMissingSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
renewer, err := c.NewLifetimeWatcher(i)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
renewer.renewBehavior = RenewBehaviorErrorOnErrors
|
||||||
|
renewer.errLifetimeWatcherNotRenewable = ErrRenewerNotRenewable
|
||||||
|
renewer.errLifetimeWatcherNoSecretData = ErrRenewerNoSecretData
|
||||||
|
return renewer, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoneCh returns the channel where the renewer will publish when renewal stops.
|
||||||
|
// If there is an error, this will be an error.
|
||||||
|
func (r *LifetimeWatcher) DoneCh() <-chan error {
|
||||||
|
return r.doneCh
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenewCh is a channel that receives a message when a successful renewal takes
|
||||||
|
// place and includes metadata about the renewal.
|
||||||
|
func (r *LifetimeWatcher) RenewCh() <-chan *RenewOutput {
|
||||||
|
return r.renewCh
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the renewer.
|
||||||
|
func (r *LifetimeWatcher) Stop() {
|
||||||
|
r.l.Lock()
|
||||||
|
defer r.l.Unlock()
|
||||||
|
|
||||||
|
if !r.stopped {
|
||||||
|
close(r.stopCh)
|
||||||
|
r.stopped = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start starts a background process for watching the lifetime of this secret.
|
||||||
|
// If renewal is enabled, when the secret has auth data, this attempts to renew
|
||||||
|
// the auth (token); When the secret has a lease, this attempts to renew the
|
||||||
|
// lease.
|
||||||
|
func (r *LifetimeWatcher) Start() {
|
||||||
|
r.doneCh <- r.doRenew()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Renew is for comnpatibility with the legacy api.Renewer. Calling Renew
|
||||||
|
// simply chains to Start.
|
||||||
|
func (r *LifetimeWatcher) Renew() {
|
||||||
|
r.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// renewAuth is a helper for renewing authentication.
|
||||||
|
func (r *LifetimeWatcher) doRenew() error {
|
||||||
|
var nonRenewable bool
|
||||||
|
var tokenMode bool
|
||||||
|
var initLeaseDuration int
|
||||||
|
var credString string
|
||||||
|
var renewFunc func(string, int) (*Secret, error)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case r.secret.Auth != nil:
|
||||||
|
tokenMode = true
|
||||||
|
nonRenewable = !r.secret.Auth.Renewable
|
||||||
|
initLeaseDuration = r.secret.Auth.LeaseDuration
|
||||||
|
credString = r.secret.Auth.ClientToken
|
||||||
|
renewFunc = r.client.Auth().Token().RenewTokenAsSelf
|
||||||
|
default:
|
||||||
|
nonRenewable = !r.secret.Renewable
|
||||||
|
initLeaseDuration = r.secret.LeaseDuration
|
||||||
|
credString = r.secret.LeaseID
|
||||||
|
renewFunc = r.client.Sys().Renew
|
||||||
|
}
|
||||||
|
|
||||||
|
if credString == "" ||
|
||||||
|
(nonRenewable && r.renewBehavior == RenewBehaviorErrorOnErrors) {
|
||||||
|
return r.errLifetimeWatcherNotRenewable
|
||||||
|
}
|
||||||
|
|
||||||
|
initialTime := time.Now()
|
||||||
|
priorDuration := time.Duration(initLeaseDuration) * time.Second
|
||||||
|
r.calculateGrace(priorDuration)
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Check if we are stopped.
|
||||||
|
select {
|
||||||
|
case <-r.stopCh:
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
var leaseDuration time.Duration
|
||||||
|
fallbackLeaseDuration := initialTime.Add(priorDuration).Sub(time.Now())
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case nonRenewable || r.renewBehavior == RenewBehaviorRenewDisabled:
|
||||||
|
// Can't or won't renew, just keep the same expiration so we exit
|
||||||
|
// when it's reauthentication time
|
||||||
|
leaseDuration = fallbackLeaseDuration
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Renew the token
|
||||||
|
renewal, err := renewFunc(credString, r.increment)
|
||||||
|
if err != nil || renewal == nil || (tokenMode && renewal.Auth == nil) {
|
||||||
|
if r.renewBehavior == RenewBehaviorErrorOnErrors {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if renewal == nil || (tokenMode && renewal.Auth == nil) {
|
||||||
|
return r.errLifetimeWatcherNoSecretData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaseDuration = fallbackLeaseDuration
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push a message that a renewal took place.
|
||||||
|
select {
|
||||||
|
case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibly error if we are not renewable
|
||||||
|
if ((tokenMode && !renewal.Auth.Renewable) || (!tokenMode && !renewal.Renewable)) &&
|
||||||
|
r.renewBehavior == RenewBehaviorErrorOnErrors {
|
||||||
|
return r.errLifetimeWatcherNotRenewable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the lease duration
|
||||||
|
newDuration := renewal.LeaseDuration
|
||||||
|
if tokenMode {
|
||||||
|
newDuration = renewal.Auth.LeaseDuration
|
||||||
|
}
|
||||||
|
|
||||||
|
leaseDuration = time.Duration(newDuration) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
// We keep evaluating a new grace period so long as the lease is
|
||||||
|
// extending. Once it stops extending, we've hit the max and need to
|
||||||
|
// rely on the grace duration.
|
||||||
|
if leaseDuration > priorDuration {
|
||||||
|
r.calculateGrace(leaseDuration)
|
||||||
|
}
|
||||||
|
priorDuration = leaseDuration
|
||||||
|
|
||||||
|
// The sleep duration is set to 2/3 of the current lease duration plus
|
||||||
|
// 1/3 of the current grace period, which adds jitter.
|
||||||
|
sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
|
||||||
|
|
||||||
|
// If we are within grace, return now; or, if the amount of time we
|
||||||
|
// would sleep would land us in the grace period. This helps with short
|
||||||
|
// tokens; for example, you don't want a current lease duration of 4
|
||||||
|
// seconds, a grace period of 3 seconds, and end up sleeping for more
|
||||||
|
// than three of those seconds and having a very small budget of time
|
||||||
|
// to renew.
|
||||||
|
if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-r.stopCh:
|
||||||
|
return nil
|
||||||
|
case <-time.After(sleepDuration):
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleepDuration calculates the time to sleep given the base lease duration. The
|
||||||
|
// base is the resulting lease duration. It will be reduced to 1/3 and
|
||||||
|
// multiplied by a random float between 0.0 and 1.0. This extra randomness
|
||||||
|
// prevents multiple clients from all trying to renew simultaneously.
|
||||||
|
func (r *LifetimeWatcher) sleepDuration(base time.Duration) time.Duration {
|
||||||
|
sleep := float64(base)
|
||||||
|
|
||||||
|
// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
|
||||||
|
// at least one more time should the first renewal fail.
|
||||||
|
sleep = sleep / 3.0
|
||||||
|
|
||||||
|
// Use a randomness so many clients do not hit Vault simultaneously.
|
||||||
|
sleep = sleep * (r.random.Float64() + 1) / 2.0
|
||||||
|
|
||||||
|
return time.Duration(sleep)
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateGrace calculates the grace period based on a reasonable set of
|
||||||
|
// assumptions given the total lease time; it also adds some jitter to not have
|
||||||
|
// clients be in sync.
|
||||||
|
func (r *LifetimeWatcher) calculateGrace(leaseDuration time.Duration) {
|
||||||
|
if leaseDuration == 0 {
|
||||||
|
r.grace = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
leaseNanos := float64(leaseDuration.Nanoseconds())
|
||||||
|
jitterMax := 0.1 * leaseNanos
|
||||||
|
|
||||||
|
// For a given lease duration, we want to allow 80-90% of that to elapse,
|
||||||
|
// so the remaining amount is the grace period
|
||||||
|
r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Renewer = LifetimeWatcher
|
||||||
|
type RenewerInput = LifetimeWatcherInput
|
18
vendor/github.com/hashicorp/vault/api/logical.go
generated
vendored
18
vendor/github.com/hashicorp/vault/api/logical.go
generated
vendored
@ -21,8 +21,9 @@ var (
|
|||||||
// changed
|
// changed
|
||||||
DefaultWrappingTTL = "5m"
|
DefaultWrappingTTL = "5m"
|
||||||
|
|
||||||
// The default function used if no other function is set, which honors the
|
// The default function used if no other function is set. It honors the env
|
||||||
// env var and wraps `sys/wrapping/wrap`
|
// var to set the wrap TTL. The default wrap TTL will apply when when writing
|
||||||
|
// to `sys/wrapping/wrap` when the env var is not set.
|
||||||
DefaultWrappingLookupFunc = func(operation, path string) string {
|
DefaultWrappingLookupFunc = func(operation, path string) string {
|
||||||
if os.Getenv(EnvVaultWrapTTL) != "" {
|
if os.Getenv(EnvVaultWrapTTL) != "" {
|
||||||
return os.Getenv(EnvVaultWrapTTL)
|
return os.Getenv(EnvVaultWrapTTL)
|
||||||
@ -134,9 +135,20 @@ func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, erro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return c.write(path, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Logical) WriteBytes(path string, data []byte) (*Secret, error) {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/"+path)
|
||||||
|
r.BodyBytes = data
|
||||||
|
|
||||||
|
return c.write(path, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Logical) write(path string, request *Request) (*Secret, error) {
|
||||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
defer cancelFunc()
|
defer cancelFunc()
|
||||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
resp, err := c.c.RawRequestWithContext(ctx, request)
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
}
|
}
|
||||||
|
3
vendor/github.com/hashicorp/vault/api/plugin_helpers.go
generated
vendored
3
vendor/github.com/hashicorp/vault/api/plugin_helpers.go
generated
vendored
@ -118,6 +118,9 @@ func VaultPluginTLSProvider(apiTLSConfig *TLSConfig) func() (*tls.Config, error)
|
|||||||
return nil, errwrap.Wrapf("error during api client creation: {{err}}", err)
|
return nil, errwrap.Wrapf("error during api client creation: {{err}}", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset token value to make sure nothing has been set by default
|
||||||
|
client.ClearToken()
|
||||||
|
|
||||||
secret, err := client.Logical().Unwrap(unwrapToken)
|
secret, err := client.Logical().Unwrap(unwrapToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err)
|
return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err)
|
||||||
|
349
vendor/github.com/hashicorp/vault/api/renewer.go
generated
vendored
349
vendor/github.com/hashicorp/vault/api/renewer.go
generated
vendored
@ -1,349 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math/rand"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrRenewerMissingInput = errors.New("missing input to renewer")
|
|
||||||
ErrRenewerMissingSecret = errors.New("missing secret to renew")
|
|
||||||
ErrRenewerNotRenewable = errors.New("secret is not renewable")
|
|
||||||
ErrRenewerNoSecretData = errors.New("returned empty secret data")
|
|
||||||
|
|
||||||
// DefaultRenewerRenewBuffer is the default size of the buffer for renew
|
|
||||||
// messages on the channel.
|
|
||||||
DefaultRenewerRenewBuffer = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
// Renewer is a process for renewing a secret.
|
|
||||||
//
|
|
||||||
// renewer, err := client.NewRenewer(&RenewerInput{
|
|
||||||
// Secret: mySecret,
|
|
||||||
// })
|
|
||||||
// go renewer.Renew()
|
|
||||||
// defer renewer.Stop()
|
|
||||||
//
|
|
||||||
// for {
|
|
||||||
// select {
|
|
||||||
// case err := <-renewer.DoneCh():
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Renewal is now over
|
|
||||||
// case renewal := <-renewer.RenewCh():
|
|
||||||
// log.Printf("Successfully renewed: %#v", renewal)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// The `DoneCh` will return if renewal fails or if the remaining lease duration
|
|
||||||
// after a renewal is less than or equal to the grace (in number of seconds). In
|
|
||||||
// both cases, the caller should attempt a re-read of the secret. Clients should
|
|
||||||
// check the return value of the channel to see if renewal was successful.
|
|
||||||
type Renewer struct {
|
|
||||||
l sync.Mutex
|
|
||||||
|
|
||||||
client *Client
|
|
||||||
secret *Secret
|
|
||||||
grace time.Duration
|
|
||||||
random *rand.Rand
|
|
||||||
increment int
|
|
||||||
doneCh chan error
|
|
||||||
renewCh chan *RenewOutput
|
|
||||||
|
|
||||||
stopped bool
|
|
||||||
stopCh chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewerInput is used as input to the renew function.
|
|
||||||
type RenewerInput struct {
|
|
||||||
// Secret is the secret to renew
|
|
||||||
Secret *Secret
|
|
||||||
|
|
||||||
// DEPRECATED: this does not do anything.
|
|
||||||
Grace time.Duration
|
|
||||||
|
|
||||||
// Rand is the randomizer to use for underlying randomization. If not
|
|
||||||
// provided, one will be generated and seeded automatically. If provided, it
|
|
||||||
// is assumed to have already been seeded.
|
|
||||||
Rand *rand.Rand
|
|
||||||
|
|
||||||
// RenewBuffer is the size of the buffered channel where renew messages are
|
|
||||||
// dispatched.
|
|
||||||
RenewBuffer int
|
|
||||||
|
|
||||||
// The new TTL, in seconds, that should be set on the lease. The TTL set
|
|
||||||
// here may or may not be honored by the vault server, based on Vault
|
|
||||||
// configuration or any associated max TTL values.
|
|
||||||
Increment int
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewOutput is the metadata returned to the client (if it's listening) to
|
|
||||||
// renew messages.
|
|
||||||
type RenewOutput struct {
|
|
||||||
// RenewedAt is the timestamp when the renewal took place (UTC).
|
|
||||||
RenewedAt time.Time
|
|
||||||
|
|
||||||
// Secret is the underlying renewal data. It's the same struct as all data
|
|
||||||
// that is returned from Vault, but since this is renewal data, it will not
|
|
||||||
// usually include the secret itself.
|
|
||||||
Secret *Secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRenewer creates a new renewer from the given input.
|
|
||||||
func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
|
|
||||||
if i == nil {
|
|
||||||
return nil, ErrRenewerMissingInput
|
|
||||||
}
|
|
||||||
|
|
||||||
secret := i.Secret
|
|
||||||
if secret == nil {
|
|
||||||
return nil, ErrRenewerMissingSecret
|
|
||||||
}
|
|
||||||
|
|
||||||
random := i.Rand
|
|
||||||
if random == nil {
|
|
||||||
random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
|
||||||
}
|
|
||||||
|
|
||||||
renewBuffer := i.RenewBuffer
|
|
||||||
if renewBuffer == 0 {
|
|
||||||
renewBuffer = DefaultRenewerRenewBuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Renewer{
|
|
||||||
client: c,
|
|
||||||
secret: secret,
|
|
||||||
increment: i.Increment,
|
|
||||||
random: random,
|
|
||||||
doneCh: make(chan error, 1),
|
|
||||||
renewCh: make(chan *RenewOutput, renewBuffer),
|
|
||||||
|
|
||||||
stopped: false,
|
|
||||||
stopCh: make(chan struct{}),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DoneCh returns the channel where the renewer will publish when renewal stops.
|
|
||||||
// If there is an error, this will be an error.
|
|
||||||
func (r *Renewer) DoneCh() <-chan error {
|
|
||||||
return r.doneCh
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenewCh is a channel that receives a message when a successful renewal takes
|
|
||||||
// place and includes metadata about the renewal.
|
|
||||||
func (r *Renewer) RenewCh() <-chan *RenewOutput {
|
|
||||||
return r.renewCh
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop stops the renewer.
|
|
||||||
func (r *Renewer) Stop() {
|
|
||||||
r.l.Lock()
|
|
||||||
if !r.stopped {
|
|
||||||
close(r.stopCh)
|
|
||||||
r.stopped = true
|
|
||||||
}
|
|
||||||
r.l.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew starts a background process for renewing this secret. When the secret
|
|
||||||
// has auth data, this attempts to renew the auth (token). When the secret has
|
|
||||||
// a lease, this attempts to renew the lease.
|
|
||||||
func (r *Renewer) Renew() {
|
|
||||||
var result error
|
|
||||||
if r.secret.Auth != nil {
|
|
||||||
result = r.renewAuth()
|
|
||||||
} else {
|
|
||||||
result = r.renewLease()
|
|
||||||
}
|
|
||||||
|
|
||||||
r.doneCh <- result
|
|
||||||
}
|
|
||||||
|
|
||||||
// renewAuth is a helper for renewing authentication.
|
|
||||||
func (r *Renewer) renewAuth() error {
|
|
||||||
if !r.secret.Auth.Renewable || r.secret.Auth.ClientToken == "" {
|
|
||||||
return ErrRenewerNotRenewable
|
|
||||||
}
|
|
||||||
|
|
||||||
priorDuration := time.Duration(r.secret.Auth.LeaseDuration) * time.Second
|
|
||||||
r.calculateGrace(priorDuration)
|
|
||||||
|
|
||||||
client, token := r.client, r.secret.Auth.ClientToken
|
|
||||||
|
|
||||||
for {
|
|
||||||
// Check if we are stopped.
|
|
||||||
select {
|
|
||||||
case <-r.stopCh:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew the auth.
|
|
||||||
renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push a message that a renewal took place.
|
|
||||||
select {
|
|
||||||
case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// Somehow, sometimes, this happens.
|
|
||||||
if renewal == nil || renewal.Auth == nil {
|
|
||||||
return ErrRenewerNoSecretData
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing if we are not renewable
|
|
||||||
if !renewal.Auth.Renewable {
|
|
||||||
return ErrRenewerNotRenewable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab the lease duration
|
|
||||||
leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second
|
|
||||||
|
|
||||||
// We keep evaluating a new grace period so long as the lease is
|
|
||||||
// extending. Once it stops extending, we've hit the max and need to
|
|
||||||
// rely on the grace duration.
|
|
||||||
if leaseDuration > priorDuration {
|
|
||||||
r.calculateGrace(leaseDuration)
|
|
||||||
}
|
|
||||||
priorDuration = leaseDuration
|
|
||||||
|
|
||||||
// The sleep duration is set to 2/3 of the current lease duration plus
|
|
||||||
// 1/3 of the current grace period, which adds jitter.
|
|
||||||
sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
|
|
||||||
|
|
||||||
// If we are within grace, return now; or, if the amount of time we
|
|
||||||
// would sleep would land us in the grace period. This helps with short
|
|
||||||
// tokens; for example, you don't want a current lease duration of 4
|
|
||||||
// seconds, a grace period of 3 seconds, and end up sleeping for more
|
|
||||||
// than three of those seconds and having a very small budget of time
|
|
||||||
// to renew.
|
|
||||||
if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-r.stopCh:
|
|
||||||
return nil
|
|
||||||
case <-time.After(sleepDuration):
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// renewLease is a helper for renewing a lease.
|
|
||||||
func (r *Renewer) renewLease() error {
|
|
||||||
if !r.secret.Renewable || r.secret.LeaseID == "" {
|
|
||||||
return ErrRenewerNotRenewable
|
|
||||||
}
|
|
||||||
|
|
||||||
priorDuration := time.Duration(r.secret.LeaseDuration) * time.Second
|
|
||||||
r.calculateGrace(priorDuration)
|
|
||||||
|
|
||||||
client, leaseID := r.client, r.secret.LeaseID
|
|
||||||
|
|
||||||
for {
|
|
||||||
// Check if we are stopped.
|
|
||||||
select {
|
|
||||||
case <-r.stopCh:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// Renew the lease.
|
|
||||||
renewal, err := client.Sys().Renew(leaseID, r.increment)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push a message that a renewal took place.
|
|
||||||
select {
|
|
||||||
case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// Somehow, sometimes, this happens.
|
|
||||||
if renewal == nil {
|
|
||||||
return ErrRenewerNoSecretData
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do nothing if we are not renewable
|
|
||||||
if !renewal.Renewable {
|
|
||||||
return ErrRenewerNotRenewable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab the lease duration
|
|
||||||
leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second
|
|
||||||
|
|
||||||
// We keep evaluating a new grace period so long as the lease is
|
|
||||||
// extending. Once it stops extending, we've hit the max and need to
|
|
||||||
// rely on the grace duration.
|
|
||||||
if leaseDuration > priorDuration {
|
|
||||||
r.calculateGrace(leaseDuration)
|
|
||||||
}
|
|
||||||
priorDuration = leaseDuration
|
|
||||||
|
|
||||||
// The sleep duration is set to 2/3 of the current lease duration plus
|
|
||||||
// 1/3 of the current grace period, which adds jitter.
|
|
||||||
sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
|
|
||||||
|
|
||||||
// If we are within grace, return now; or, if the amount of time we
|
|
||||||
// would sleep would land us in the grace period. This helps with short
|
|
||||||
// tokens; for example, you don't want a current lease duration of 4
|
|
||||||
// seconds, a grace period of 3 seconds, and end up sleeping for more
|
|
||||||
// than three of those seconds and having a very small budget of time
|
|
||||||
// to renew.
|
|
||||||
if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-r.stopCh:
|
|
||||||
return nil
|
|
||||||
case <-time.After(sleepDuration):
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sleepDuration calculates the time to sleep given the base lease duration. The
|
|
||||||
// base is the resulting lease duration. It will be reduced to 1/3 and
|
|
||||||
// multiplied by a random float between 0.0 and 1.0. This extra randomness
|
|
||||||
// prevents multiple clients from all trying to renew simultaneously.
|
|
||||||
func (r *Renewer) sleepDuration(base time.Duration) time.Duration {
|
|
||||||
sleep := float64(base)
|
|
||||||
|
|
||||||
// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
|
|
||||||
// at least one more time should the first renewal fail.
|
|
||||||
sleep = sleep / 3.0
|
|
||||||
|
|
||||||
// Use a randomness so many clients do not hit Vault simultaneously.
|
|
||||||
sleep = sleep * (r.random.Float64() + 1) / 2.0
|
|
||||||
|
|
||||||
return time.Duration(sleep)
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateGrace calculates the grace period based on a reasonable set of
|
|
||||||
// assumptions given the total lease time; it also adds some jitter to not have
|
|
||||||
// clients be in sync.
|
|
||||||
func (r *Renewer) calculateGrace(leaseDuration time.Duration) {
|
|
||||||
if leaseDuration == 0 {
|
|
||||||
r.grace = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
leaseNanos := float64(leaseDuration.Nanoseconds())
|
|
||||||
jitterMax := 0.1 * leaseNanos
|
|
||||||
|
|
||||||
// For a given lease duration, we want to allow 80-90% of that to elapse,
|
|
||||||
// so the remaining amount is the grace period
|
|
||||||
r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax))
|
|
||||||
}
|
|
3
vendor/github.com/hashicorp/vault/api/request.go
generated
vendored
3
vendor/github.com/hashicorp/vault/api/request.go
generated
vendored
@ -18,6 +18,7 @@ import (
|
|||||||
type Request struct {
|
type Request struct {
|
||||||
Method string
|
Method string
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
|
Host string
|
||||||
Params url.Values
|
Params url.Values
|
||||||
Headers http.Header
|
Headers http.Header
|
||||||
ClientToken string
|
ClientToken string
|
||||||
@ -115,7 +116,7 @@ func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) {
|
|||||||
req.URL.User = r.URL.User
|
req.URL.User = r.URL.User
|
||||||
req.URL.Scheme = r.URL.Scheme
|
req.URL.Scheme = r.URL.Scheme
|
||||||
req.URL.Host = r.URL.Host
|
req.URL.Host = r.URL.Host
|
||||||
req.Host = r.URL.Host
|
req.Host = r.Host
|
||||||
|
|
||||||
if r.Headers != nil {
|
if r.Headers != nil {
|
||||||
for header, vals := range r.Headers {
|
for header, vals := range r.Headers {
|
||||||
|
4
vendor/github.com/hashicorp/vault/api/response.go
generated
vendored
4
vendor/github.com/hashicorp/vault/api/response.go
generated
vendored
@ -27,8 +27,8 @@ func (r *Response) DecodeJSON(out interface{}) error {
|
|||||||
// body must still be closed manually.
|
// body must still be closed manually.
|
||||||
func (r *Response) Error() error {
|
func (r *Response) Error() error {
|
||||||
// 200 to 399 are okay status codes. 429 is the code for health status of
|
// 200 to 399 are okay status codes. 429 is the code for health status of
|
||||||
// standby nodes.
|
// standby nodes, otherwise, 429 is treated as quota limit reached.
|
||||||
if (r.StatusCode >= 200 && r.StatusCode < 400) || r.StatusCode == 429 {
|
if (r.StatusCode >= 200 && r.StatusCode < 400) || (r.StatusCode == 429 && r.Request.URL.Path == "/v1/sys/health") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
vendor/github.com/hashicorp/vault/api/ssh_agent.go
generated
vendored
7
vendor/github.com/hashicorp/vault/api/ssh_agent.go
generated
vendored
@ -60,6 +60,7 @@ type SSHVerifyResponse struct {
|
|||||||
type SSHHelperConfig struct {
|
type SSHHelperConfig struct {
|
||||||
VaultAddr string `hcl:"vault_addr"`
|
VaultAddr string `hcl:"vault_addr"`
|
||||||
SSHMountPoint string `hcl:"ssh_mount_point"`
|
SSHMountPoint string `hcl:"ssh_mount_point"`
|
||||||
|
Namespace string `hcl:"namespace"`
|
||||||
CACert string `hcl:"ca_cert"`
|
CACert string `hcl:"ca_cert"`
|
||||||
CAPath string `hcl:"ca_path"`
|
CAPath string `hcl:"ca_path"`
|
||||||
AllowedCidrList string `hcl:"allowed_cidr_list"`
|
AllowedCidrList string `hcl:"allowed_cidr_list"`
|
||||||
@ -123,6 +124,11 @@ func (c *SSHHelperConfig) NewClient() (*Client, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure namespace
|
||||||
|
if c.Namespace != "" {
|
||||||
|
client.SetNamespace(c.Namespace)
|
||||||
|
}
|
||||||
|
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +161,7 @@ func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
|
|||||||
valid := []string{
|
valid := []string{
|
||||||
"vault_addr",
|
"vault_addr",
|
||||||
"ssh_mount_point",
|
"ssh_mount_point",
|
||||||
|
"namespace",
|
||||||
"ca_cert",
|
"ca_cert",
|
||||||
"ca_path",
|
"ca_path",
|
||||||
"allowed_cidr_list",
|
"allowed_cidr_list",
|
||||||
|
2
vendor/github.com/hashicorp/vault/api/sys_audit.go
generated
vendored
2
vendor/github.com/hashicorp/vault/api/sys_audit.go
generated
vendored
@ -116,7 +116,7 @@ func (c *Sys) DisableAudit(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structures for the requests/resposne are all down here. They aren't
|
// Structures for the requests/response are all down here. They aren't
|
||||||
// individually documented because the map almost directly to the raw HTTP API
|
// individually documented because the map almost directly to the raw HTTP API
|
||||||
// documentation. Please refer to that documentation for more details.
|
// documentation. Please refer to that documentation for more details.
|
||||||
|
|
||||||
|
16
vendor/github.com/hashicorp/vault/api/sys_generate_root.go
generated
vendored
16
vendor/github.com/hashicorp/vault/api/sys_generate_root.go
generated
vendored
@ -10,6 +10,10 @@ func (c *Sys) GenerateDROperationTokenStatus() (*GenerateRootStatusResponse, err
|
|||||||
return c.generateRootStatusCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
|
return c.generateRootStatusCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRecoveryOperationTokenStatus() (*GenerateRootStatusResponse, error) {
|
||||||
|
return c.generateRootStatusCommon("/v1/sys/generate-recovery-token/attempt")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Sys) generateRootStatusCommon(path string) (*GenerateRootStatusResponse, error) {
|
func (c *Sys) generateRootStatusCommon(path string) (*GenerateRootStatusResponse, error) {
|
||||||
r := c.c.NewRequest("GET", path)
|
r := c.c.NewRequest("GET", path)
|
||||||
|
|
||||||
@ -34,6 +38,10 @@ func (c *Sys) GenerateDROperationTokenInit(otp, pgpKey string) (*GenerateRootSta
|
|||||||
return c.generateRootInitCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt", otp, pgpKey)
|
return c.generateRootInitCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt", otp, pgpKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRecoveryOperationTokenInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) {
|
||||||
|
return c.generateRootInitCommon("/v1/sys/generate-recovery-token/attempt", otp, pgpKey)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Sys) generateRootInitCommon(path, otp, pgpKey string) (*GenerateRootStatusResponse, error) {
|
func (c *Sys) generateRootInitCommon(path, otp, pgpKey string) (*GenerateRootStatusResponse, error) {
|
||||||
body := map[string]interface{}{
|
body := map[string]interface{}{
|
||||||
"otp": otp,
|
"otp": otp,
|
||||||
@ -66,6 +74,10 @@ func (c *Sys) GenerateDROperationTokenCancel() error {
|
|||||||
return c.generateRootCancelCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
|
return c.generateRootCancelCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRecoveryOperationTokenCancel() error {
|
||||||
|
return c.generateRootCancelCommon("/v1/sys/generate-recovery-token/attempt")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Sys) generateRootCancelCommon(path string) error {
|
func (c *Sys) generateRootCancelCommon(path string) error {
|
||||||
r := c.c.NewRequest("DELETE", path)
|
r := c.c.NewRequest("DELETE", path)
|
||||||
|
|
||||||
@ -86,6 +98,10 @@ func (c *Sys) GenerateDROperationTokenUpdate(shard, nonce string) (*GenerateRoot
|
|||||||
return c.generateRootUpdateCommon("/v1/sys/replication/dr/secondary/generate-operation-token/update", shard, nonce)
|
return c.generateRootUpdateCommon("/v1/sys/replication/dr/secondary/generate-operation-token/update", shard, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Sys) GenerateRecoveryOperationTokenUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) {
|
||||||
|
return c.generateRootUpdateCommon("/v1/sys/generate-recovery-token/update", shard, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Sys) generateRootUpdateCommon(path, shard, nonce string) (*GenerateRootStatusResponse, error) {
|
func (c *Sys) generateRootUpdateCommon(path, shard, nonce string) (*GenerateRootStatusResponse, error) {
|
||||||
body := map[string]interface{}{
|
body := map[string]interface{}{
|
||||||
"key": shard,
|
"key": shard,
|
||||||
|
2
vendor/github.com/hashicorp/vault/api/sys_leader.go
generated
vendored
2
vendor/github.com/hashicorp/vault/api/sys_leader.go
generated
vendored
@ -26,4 +26,6 @@ type LeaderResponse struct {
|
|||||||
PerfStandby bool `json:"performance_standby"`
|
PerfStandby bool `json:"performance_standby"`
|
||||||
PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"`
|
PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"`
|
||||||
LastWAL uint64 `json:"last_wal"`
|
LastWAL uint64 `json:"last_wal"`
|
||||||
|
RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"`
|
||||||
|
RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"`
|
||||||
}
|
}
|
||||||
|
8
vendor/github.com/hashicorp/vault/api/sys_leases.go
generated
vendored
8
vendor/github.com/hashicorp/vault/api/sys_leases.go
generated
vendored
@ -28,7 +28,13 @@ func (c *Sys) Renew(id string, increment int) (*Secret, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Sys) Revoke(id string) error {
|
func (c *Sys) Revoke(id string) error {
|
||||||
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke/"+id)
|
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke")
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"lease_id": id,
|
||||||
|
}
|
||||||
|
if err := r.SetJSONBody(body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
defer cancelFunc()
|
defer cancelFunc()
|
||||||
|
64
vendor/github.com/hashicorp/vault/api/sys_monitor.go
generated
vendored
Normal file
64
vendor/github.com/hashicorp/vault/api/sys_monitor.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Monitor returns a channel that outputs strings containing the log messages
|
||||||
|
// coming from the server.
|
||||||
|
func (c *Sys) Monitor(ctx context.Context, logLevel string) (chan string, error) {
|
||||||
|
r := c.c.NewRequest("GET", "/v1/sys/monitor")
|
||||||
|
|
||||||
|
if logLevel == "" {
|
||||||
|
r.Params.Add("log_level", "info")
|
||||||
|
} else {
|
||||||
|
r.Params.Add("log_level", logLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logCh := make(chan string, 64)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
scanner := bufio.NewScanner(resp.Body)
|
||||||
|
droppedCount := 0
|
||||||
|
|
||||||
|
defer close(logCh)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !scanner.Scan() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logMessage := scanner.Text()
|
||||||
|
|
||||||
|
if droppedCount > 0 {
|
||||||
|
select {
|
||||||
|
case logCh <- fmt.Sprintf("Monitor dropped %d logs during monitor request\n", droppedCount):
|
||||||
|
droppedCount = 0
|
||||||
|
default:
|
||||||
|
droppedCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case logCh <- logMessage:
|
||||||
|
default:
|
||||||
|
droppedCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return logCh, nil
|
||||||
|
}
|
30
vendor/github.com/hashicorp/vault/api/sys_mounts.go
generated
vendored
30
vendor/github.com/hashicorp/vault/api/sys_mounts.go
generated
vendored
@ -129,12 +129,13 @@ func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MountInput struct {
|
type MountInput struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Config MountConfigInput `json:"config"`
|
Config MountConfigInput `json:"config"`
|
||||||
Local bool `json:"local"`
|
Local bool `json:"local"`
|
||||||
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
||||||
Options map[string]string `json:"options"`
|
ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"`
|
||||||
|
Options map[string]string `json:"options"`
|
||||||
|
|
||||||
// Deprecated: Newer server responses should be returning this information in the
|
// Deprecated: Newer server responses should be returning this information in the
|
||||||
// Type field (json: "type") instead.
|
// Type field (json: "type") instead.
|
||||||
@ -159,14 +160,15 @@ type MountConfigInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MountOutput struct {
|
type MountOutput struct {
|
||||||
UUID string `json:"uuid"`
|
UUID string `json:"uuid"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Accessor string `json:"accessor"`
|
Accessor string `json:"accessor"`
|
||||||
Config MountConfigOutput `json:"config"`
|
Config MountConfigOutput `json:"config"`
|
||||||
Options map[string]string `json:"options"`
|
Options map[string]string `json:"options"`
|
||||||
Local bool `json:"local"`
|
Local bool `json:"local"`
|
||||||
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
||||||
|
ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MountConfigOutput struct {
|
type MountConfigOutput struct {
|
||||||
|
101
vendor/github.com/hashicorp/vault/api/sys_plugins.go
generated
vendored
101
vendor/github.com/hashicorp/vault/api/sys_plugins.go
generated
vendored
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
@ -225,6 +226,106 @@ func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReloadPluginInput is used as input to the ReloadPlugin function.
|
||||||
|
type ReloadPluginInput struct {
|
||||||
|
// Plugin is the name of the plugin to reload, as registered in the plugin catalog
|
||||||
|
Plugin string `json:"plugin"`
|
||||||
|
|
||||||
|
// Mounts is the array of string mount paths of the plugin backends to reload
|
||||||
|
Mounts []string `json:"mounts"`
|
||||||
|
|
||||||
|
// Scope is the scope of the plugin reload
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadPlugin reloads mounted plugin backends, possibly returning
|
||||||
|
// reloadId for a cluster scoped reload
|
||||||
|
func (c *Sys) ReloadPlugin(i *ReloadPluginInput) (string, error) {
|
||||||
|
path := "/v1/sys/plugins/reload/backend"
|
||||||
|
req := c.c.NewRequest(http.MethodPut, path)
|
||||||
|
|
||||||
|
if err := req.SetJSONBody(i); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
defer cancelFunc()
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequestWithContext(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if i.Scope == "global" {
|
||||||
|
// Get the reload id
|
||||||
|
secret, parseErr := ParseSecret(resp.Body)
|
||||||
|
if parseErr != nil {
|
||||||
|
return "", parseErr
|
||||||
|
}
|
||||||
|
if _, ok := secret.Data["reload_id"]; ok {
|
||||||
|
return secret.Data["reload_id"].(string), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadStatus is the status of an individual node's plugin reload
|
||||||
|
type ReloadStatus struct {
|
||||||
|
Timestamp time.Time `json:"timestamp" mapstructure:"timestamp"`
|
||||||
|
Error string `json:"error" mapstructure:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadStatusResponse is the combined response of all known completed plugin reloads
|
||||||
|
type ReloadStatusResponse struct {
|
||||||
|
ReloadID string `mapstructure:"reload_id"`
|
||||||
|
Results map[string]*ReloadStatus `mapstructure:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadPluginStatusInput is used as input to the ReloadStatusPlugin function.
|
||||||
|
type ReloadPluginStatusInput struct {
|
||||||
|
// ReloadID is the ID of the reload operation
|
||||||
|
ReloadID string `json:"reload_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReloadPluginStatus retrieves the status of a reload operation
|
||||||
|
func (c *Sys) ReloadPluginStatus(reloadStatusInput *ReloadPluginStatusInput) (*ReloadStatusResponse, error) {
|
||||||
|
path := "/v1/sys/plugins/reload/backend/status"
|
||||||
|
req := c.c.NewRequest(http.MethodGet, path)
|
||||||
|
req.Params.Add("reload_id", reloadStatusInput.ReloadID)
|
||||||
|
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
defer cancelFunc()
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequestWithContext(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp != nil {
|
||||||
|
secret, parseErr := ParseSecret(resp.Body)
|
||||||
|
if parseErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ReloadStatusResponse
|
||||||
|
d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||||
|
DecodeHook: mapstructure.StringToTimeHookFunc(time.RFC3339),
|
||||||
|
Result: &r,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = d.Decode(secret.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &r, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// catalogPathByType is a helper to construct the proper API path by plugin type
|
// catalogPathByType is a helper to construct the proper API path by plugin type
|
||||||
func catalogPathByType(pluginType consts.PluginType, name string) string {
|
func catalogPathByType(pluginType consts.PluginType, name string) string {
|
||||||
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name)
|
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name)
|
||||||
|
31
vendor/github.com/hashicorp/vault/api/sys_raft.go
generated
vendored
31
vendor/github.com/hashicorp/vault/api/sys_raft.go
generated
vendored
@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@ -16,10 +17,11 @@ type RaftJoinResponse struct {
|
|||||||
// RaftJoinRequest represents the parameters consumed by the raft join API
|
// RaftJoinRequest represents the parameters consumed by the raft join API
|
||||||
type RaftJoinRequest struct {
|
type RaftJoinRequest struct {
|
||||||
LeaderAPIAddr string `json:"leader_api_addr"`
|
LeaderAPIAddr string `json:"leader_api_addr"`
|
||||||
LeaderCACert string `json:"leader_ca_cert":`
|
LeaderCACert string `json:"leader_ca_cert"`
|
||||||
LeaderClientCert string `json:"leader_client_cert"`
|
LeaderClientCert string `json:"leader_client_cert"`
|
||||||
LeaderClientKey string `json:"leader_client_key"`
|
LeaderClientKey string `json:"leader_client_key"`
|
||||||
Retry bool `json:"retry"`
|
Retry bool `json:"retry"`
|
||||||
|
NonVoter bool `json:"non_voter"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RaftJoin adds the node from which this call is invoked from to the raft
|
// RaftJoin adds the node from which this call is invoked from to the raft
|
||||||
@ -90,10 +92,37 @@ func (c *Sys) RaftSnapshot(snapWriter io.Writer) error {
|
|||||||
// to determine if the body contains error message.
|
// to determine if the body contains error message.
|
||||||
var result *Response
|
var result *Response
|
||||||
resp, err := c.c.config.HttpClient.Do(req)
|
resp, err := c.c.config.HttpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for a redirect, only allowing for a single redirect
|
||||||
|
if resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307 {
|
||||||
|
// Parse the updated location
|
||||||
|
respLoc, err := resp.Location()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a protocol downgrade doesn't happen
|
||||||
|
if req.URL.Scheme == "https" && respLoc.Scheme != "https" {
|
||||||
|
return fmt.Errorf("redirect would cause protocol downgrade")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the request
|
||||||
|
req.URL = respLoc
|
||||||
|
|
||||||
|
// Retry the request
|
||||||
|
resp, err = c.c.config.HttpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result = &Response{Response: resp}
|
result = &Response{Response: resp}
|
||||||
if err := result.Error(); err != nil {
|
if err := result.Error(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
1
vendor/github.com/hashicorp/vault/api/sys_seal.go
generated
vendored
1
vendor/github.com/hashicorp/vault/api/sys_seal.go
generated
vendored
@ -77,6 +77,7 @@ type SealStatusResponse struct {
|
|||||||
ClusterName string `json:"cluster_name,omitempty"`
|
ClusterName string `json:"cluster_name,omitempty"`
|
||||||
ClusterID string `json:"cluster_id,omitempty"`
|
ClusterID string `json:"cluster_id,omitempty"`
|
||||||
RecoverySeal bool `json:"recovery_seal"`
|
RecoverySeal bool `json:"recovery_seal"`
|
||||||
|
StorageType string `json:"storage_type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnsealOpts struct {
|
type UnsealOpts struct {
|
||||||
|
11
vendor/github.com/hashicorp/vault/sdk/helper/consts/consts.go
generated
vendored
11
vendor/github.com/hashicorp/vault/sdk/helper/consts/consts.go
generated
vendored
@ -12,12 +12,15 @@ const (
|
|||||||
// AuthHeaderName is the name of the header containing the token.
|
// AuthHeaderName is the name of the header containing the token.
|
||||||
AuthHeaderName = "X-Vault-Token"
|
AuthHeaderName = "X-Vault-Token"
|
||||||
|
|
||||||
|
// RequestHeaderName is the name of the header used by the Agent for
|
||||||
|
// SSRF protection.
|
||||||
|
RequestHeaderName = "X-Vault-Request"
|
||||||
|
|
||||||
// PerformanceReplicationALPN is the negotiated protocol used for
|
// PerformanceReplicationALPN is the negotiated protocol used for
|
||||||
// performance replication.
|
// performance replication.
|
||||||
PerformanceReplicationALPN = "replication_v1"
|
PerformanceReplicationALPN = "replication_v1"
|
||||||
|
|
||||||
// DRReplicationALPN is the negotiated protocol used for
|
// DRReplicationALPN is the negotiated protocol used for dr replication.
|
||||||
// dr replication.
|
|
||||||
DRReplicationALPN = "replication_dr_v1"
|
DRReplicationALPN = "replication_dr_v1"
|
||||||
|
|
||||||
PerfStandbyALPN = "perf_standby_v1"
|
PerfStandbyALPN = "perf_standby_v1"
|
||||||
@ -25,4 +28,8 @@ const (
|
|||||||
RequestForwardingALPN = "req_fw_sb-act_v1"
|
RequestForwardingALPN = "req_fw_sb-act_v1"
|
||||||
|
|
||||||
RaftStorageALPN = "raft_storage_v1"
|
RaftStorageALPN = "raft_storage_v1"
|
||||||
|
|
||||||
|
// ReplicationResolverALPN is the negotiated protocol used for
|
||||||
|
// resolving replicaiton addresses
|
||||||
|
ReplicationResolverALPN = "replication_resolver_v1"
|
||||||
)
|
)
|
||||||
|
5
vendor/github.com/hashicorp/vault/sdk/helper/consts/replication.go
generated
vendored
5
vendor/github.com/hashicorp/vault/sdk/helper/consts/replication.go
generated
vendored
@ -18,6 +18,7 @@ const (
|
|||||||
// manager. It should contain a character that is not allowed in secondary
|
// manager. It should contain a character that is not allowed in secondary
|
||||||
// ids to ensure it doesn't collide.
|
// ids to ensure it doesn't collide.
|
||||||
CurrentReplicatedSecondaryIdentifier = ".current"
|
CurrentReplicatedSecondaryIdentifier = ".current"
|
||||||
|
CoreFeatureFlagPath = "core/cluster/feature-flags"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReplicationState uint32
|
type ReplicationState uint32
|
||||||
@ -144,6 +145,10 @@ func (r ReplicationState) GetPerformanceString() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r ReplicationState) IsPrimaryState() bool {
|
||||||
|
return r.HasState(ReplicationPerformancePrimary | ReplicationDRPrimary)
|
||||||
|
}
|
||||||
|
|
||||||
func (r ReplicationState) HasState(flag ReplicationState) bool { return r&flag != 0 }
|
func (r ReplicationState) HasState(flag ReplicationState) bool { return r&flag != 0 }
|
||||||
func (r *ReplicationState) AddState(flag ReplicationState) { *r |= flag }
|
func (r *ReplicationState) AddState(flag ReplicationState) { *r |= flag }
|
||||||
func (r *ReplicationState) ClearState(flag ReplicationState) { *r &= ^flag }
|
func (r *ReplicationState) ClearState(flag ReplicationState) { *r &= ^flag }
|
||||||
|
3
vendor/github.com/pierrec/lz4/.gitignore
generated
vendored
3
vendor/github.com/pierrec/lz4/.gitignore
generated
vendored
@ -30,4 +30,5 @@ Temporary Items
|
|||||||
|
|
||||||
# End of https://www.gitignore.io/api/macos
|
# End of https://www.gitignore.io/api/macos
|
||||||
|
|
||||||
lz4c/lz4c
|
cmd/*/*exe
|
||||||
|
.idea
|
8
vendor/github.com/pierrec/lz4/.travis.yml
generated
vendored
8
vendor/github.com/pierrec/lz4/.travis.yml
generated
vendored
@ -1,9 +1,13 @@
|
|||||||
language: go
|
language: go
|
||||||
|
|
||||||
|
env:
|
||||||
|
- GO111MODULE=off
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.8.x
|
|
||||||
- 1.9.x
|
- 1.9.x
|
||||||
- 1.10.x
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
|
- 1.12.x
|
||||||
- master
|
- master
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
@ -16,3 +20,5 @@ sudo: false
|
|||||||
script:
|
script:
|
||||||
- go test -v -cpu=2
|
- go test -v -cpu=2
|
||||||
- go test -v -cpu=2 -race
|
- go test -v -cpu=2 -race
|
||||||
|
- go test -v -cpu=2 -tags noasm
|
||||||
|
- go test -v -cpu=2 -race -tags noasm
|
||||||
|
96
vendor/github.com/pierrec/lz4/README.md
generated
vendored
96
vendor/github.com/pierrec/lz4/README.md
generated
vendored
@ -1,24 +1,90 @@
|
|||||||
[![godoc](https://godoc.org/github.com/pierrec/lz4?status.png)](https://godoc.org/github.com/pierrec/lz4)
|
# lz4 : LZ4 compression in pure Go
|
||||||
|
|
||||||
# lz4
|
[![GoDoc](https://godoc.org/github.com/pierrec/lz4?status.svg)](https://godoc.org/github.com/pierrec/lz4)
|
||||||
LZ4 compression and decompression in pure Go.
|
[![Build Status](https://travis-ci.org/pierrec/lz4.svg?branch=master)](https://travis-ci.org/pierrec/lz4)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/pierrec/lz4)](https://goreportcard.com/report/github.com/pierrec/lz4)
|
||||||
|
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/pierrec/lz4.svg?style=social)](https://github.com/pierrec/lz4/tags)
|
||||||
|
|
||||||
## Usage
|
## Overview
|
||||||
|
|
||||||
```go
|
This package provides a streaming interface to [LZ4 data streams](http://fastcompression.blogspot.fr/2013/04/lz4-streaming-format-final.html) as well as low level compress and uncompress functions for LZ4 data blocks.
|
||||||
import "github.com/pierrec/lz4"
|
The implementation is based on the reference C [one](https://github.com/lz4/lz4).
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Assuming you have the go toolchain installed:
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/pierrec/lz4
|
||||||
```
|
```
|
||||||
|
|
||||||
## Description
|
There is a command line interface tool to compress and decompress LZ4 files.
|
||||||
Package lz4 implements reading and writing lz4 compressed data (a frame),
|
|
||||||
as specified in http://fastcompression.blogspot.fr/2013/04/lz4-streaming-format-final.html.
|
|
||||||
|
|
||||||
This package is **compatible with the LZ4 frame format** although the block level compression
|
```
|
||||||
and decompression functions are exposed and are fully compatible with the lz4 block format
|
go install github.com/pierrec/lz4/cmd/lz4c
|
||||||
definition, they are low level and should not be used directly.
|
```
|
||||||
|
|
||||||
For a complete description of an lz4 compressed block, see:
|
Usage
|
||||||
http://fastcompression.blogspot.fr/2011/05/lz4-explained.html
|
|
||||||
|
|
||||||
See https://github.com/Cyan4973/lz4 for the reference C implementation.
|
```
|
||||||
|
Usage of lz4c:
|
||||||
|
-version
|
||||||
|
print the program version
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
Compress the given files or from stdin to stdout.
|
||||||
|
compress [arguments] [<file name> ...]
|
||||||
|
-bc
|
||||||
|
enable block checksum
|
||||||
|
-l int
|
||||||
|
compression level (0=fastest)
|
||||||
|
-sc
|
||||||
|
disable stream checksum
|
||||||
|
-size string
|
||||||
|
block max size [64K,256K,1M,4M] (default "4M")
|
||||||
|
|
||||||
|
Uncompress the given files or from stdin to stdout.
|
||||||
|
uncompress [arguments] [<file name> ...]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```
|
||||||
|
// Compress and uncompress an input string.
|
||||||
|
s := "hello world"
|
||||||
|
r := strings.NewReader(s)
|
||||||
|
|
||||||
|
// The pipe will uncompress the data from the writer.
|
||||||
|
pr, pw := io.Pipe()
|
||||||
|
zw := lz4.NewWriter(pw)
|
||||||
|
zr := lz4.NewReader(pr)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// Compress the input string.
|
||||||
|
_, _ = io.Copy(zw, r)
|
||||||
|
_ = zw.Close() // Make sure the writer is closed
|
||||||
|
_ = pw.Close() // Terminate the pipe
|
||||||
|
}()
|
||||||
|
|
||||||
|
_, _ = io.Copy(os.Stdout, zr)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello world
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are very welcome for bug fixing, performance improvements...!
|
||||||
|
|
||||||
|
- Open an issue with a proper description
|
||||||
|
- Send a pull request with appropriate test case(s)
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
Thanks to all [contributors](https://github.com/pierrec/lz4/graphs/contributors) so far!
|
||||||
|
|
||||||
|
Special thanks to [@Zariel](https://github.com/Zariel) for his asm implementation of the decoder.
|
||||||
|
|
||||||
|
Special thanks to [@klauspost](https://github.com/klauspost) for his work on optimizing the code.
|
||||||
|
312
vendor/github.com/pierrec/lz4/block.go
generated
vendored
312
vendor/github.com/pierrec/lz4/block.go
generated
vendored
@ -2,21 +2,14 @@ package lz4
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"math/bits"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// blockHash hashes the lower 6 bytes into a value < htSize.
|
||||||
// ErrInvalidSourceShortBuffer is returned by UncompressBlock or CompressBLock when a compressed
|
func blockHash(x uint64) uint32 {
|
||||||
// block is corrupted or the destination buffer is not large enough for the uncompressed data.
|
const prime6bytes = 227718039650203
|
||||||
ErrInvalidSourceShortBuffer = errors.New("lz4: invalid source or destination buffer too short")
|
return uint32(((x << (64 - 48)) * prime6bytes) >> (64 - hashLog))
|
||||||
// ErrInvalid is returned when reading an invalid LZ4 archive.
|
|
||||||
ErrInvalid = errors.New("lz4: bad magic number")
|
|
||||||
)
|
|
||||||
|
|
||||||
// blockHash hashes 4 bytes into a value < winSize.
|
|
||||||
func blockHash(x uint32) uint32 {
|
|
||||||
const hasher uint32 = 2654435761 // Knuth multiplicative hash.
|
|
||||||
return x * hasher >> hashShift
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompressBlockBound returns the maximum size of a given buffer of size n, when not compressible.
|
// CompressBlockBound returns the maximum size of a given buffer of size n, when not compressible.
|
||||||
@ -30,137 +23,127 @@ func CompressBlockBound(n int) int {
|
|||||||
// The destination buffer must be sized appropriately.
|
// The destination buffer must be sized appropriately.
|
||||||
//
|
//
|
||||||
// An error is returned if the source data is invalid or the destination buffer is too small.
|
// An error is returned if the source data is invalid or the destination buffer is too small.
|
||||||
func UncompressBlock(src, dst []byte) (si int, err error) {
|
func UncompressBlock(src, dst []byte) (int, error) {
|
||||||
defer func() {
|
if len(src) == 0 {
|
||||||
// It is now faster to let the runtime panic and recover on out of bound slice access
|
|
||||||
// than checking indices as we go along.
|
|
||||||
if recover() != nil {
|
|
||||||
err = ErrInvalidSourceShortBuffer
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
sn := len(src)
|
|
||||||
if sn == 0 {
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
var di int
|
if di := decodeBlock(dst, src); di >= 0 {
|
||||||
|
return di, nil
|
||||||
for {
|
|
||||||
// Literals and match lengths (token).
|
|
||||||
b := int(src[si])
|
|
||||||
si++
|
|
||||||
|
|
||||||
// Literals.
|
|
||||||
if lLen := b >> 4; lLen > 0 {
|
|
||||||
if lLen == 0xF {
|
|
||||||
for src[si] == 0xFF {
|
|
||||||
lLen += 0xFF
|
|
||||||
si++
|
|
||||||
}
|
|
||||||
lLen += int(src[si])
|
|
||||||
si++
|
|
||||||
}
|
|
||||||
i := si
|
|
||||||
si += lLen
|
|
||||||
di += copy(dst[di:], src[i:si])
|
|
||||||
|
|
||||||
if si >= sn {
|
|
||||||
return di, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
si++
|
|
||||||
_ = src[si] // Bound check elimination.
|
|
||||||
offset := int(src[si-1]) | int(src[si])<<8
|
|
||||||
si++
|
|
||||||
|
|
||||||
// Match.
|
|
||||||
mLen := b & 0xF
|
|
||||||
if mLen == 0xF {
|
|
||||||
for src[si] == 0xFF {
|
|
||||||
mLen += 0xFF
|
|
||||||
si++
|
|
||||||
}
|
|
||||||
mLen += int(src[si])
|
|
||||||
si++
|
|
||||||
}
|
|
||||||
mLen += minMatch
|
|
||||||
|
|
||||||
// Copy the match.
|
|
||||||
i := di - offset
|
|
||||||
if offset > 0 && mLen >= offset {
|
|
||||||
// Efficiently copy the match dst[di-offset:di] into the dst slice.
|
|
||||||
bytesToCopy := offset * (mLen / offset)
|
|
||||||
expanded := dst[i:]
|
|
||||||
for n := offset; n <= bytesToCopy+offset; n *= 2 {
|
|
||||||
copy(expanded[n:], expanded[:n])
|
|
||||||
}
|
|
||||||
di += bytesToCopy
|
|
||||||
mLen -= bytesToCopy
|
|
||||||
}
|
|
||||||
di += copy(dst[di:], dst[i:i+mLen])
|
|
||||||
}
|
}
|
||||||
|
return 0, ErrInvalidSourceShortBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompressBlock compresses the source buffer into the destination one.
|
// CompressBlock compresses the source buffer into the destination one.
|
||||||
// This is the fast version of LZ4 compression and also the default one.
|
// This is the fast version of LZ4 compression and also the default one.
|
||||||
// The size of hashTable must be at least 64Kb.
|
|
||||||
//
|
//
|
||||||
// The size of the compressed data is returned. If it is 0 and no error, then the data is incompressible.
|
// The argument hashTable is scratch space for a hash table used by the
|
||||||
|
// compressor. If provided, it should have length at least 1<<16. If it is
|
||||||
|
// shorter (or nil), CompressBlock allocates its own hash table.
|
||||||
|
//
|
||||||
|
// The size of the compressed data is returned.
|
||||||
|
//
|
||||||
|
// If the destination buffer size is lower than CompressBlockBound and
|
||||||
|
// the compressed size is 0 and no error, then the data is incompressible.
|
||||||
//
|
//
|
||||||
// An error is returned if the destination buffer is too small.
|
// An error is returned if the destination buffer is too small.
|
||||||
func CompressBlock(src, dst []byte, hashTable []int) (di int, err error) {
|
func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
|
||||||
defer func() {
|
defer recoverBlock(&err)
|
||||||
if recover() != nil {
|
|
||||||
err = ErrInvalidSourceShortBuffer
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
sn, dn := len(src)-mfLimit, len(dst)
|
// Return 0, nil only if the destination buffer size is < CompressBlockBound.
|
||||||
if sn <= 0 || dn == 0 {
|
isNotCompressible := len(dst) < CompressBlockBound(len(src))
|
||||||
return 0, nil
|
|
||||||
|
// adaptSkipLog sets how quickly the compressor begins skipping blocks when data is incompressible.
|
||||||
|
// This significantly speeds up incompressible data and usually has very small impact on compression.
|
||||||
|
// bytes to skip = 1 + (bytes since last match >> adaptSkipLog)
|
||||||
|
const adaptSkipLog = 7
|
||||||
|
if len(hashTable) < htSize {
|
||||||
|
htIface := htPool.Get()
|
||||||
|
defer htPool.Put(htIface)
|
||||||
|
hashTable = (*(htIface).(*[htSize]int))[:]
|
||||||
|
}
|
||||||
|
// Prove to the compiler the table has at least htSize elements.
|
||||||
|
// The compiler can see that "uint32() >> hashShift" cannot be out of bounds.
|
||||||
|
hashTable = hashTable[:htSize]
|
||||||
|
|
||||||
|
// si: Current position of the search.
|
||||||
|
// anchor: Position of the current literals.
|
||||||
|
var si, di, anchor int
|
||||||
|
sn := len(src) - mfLimit
|
||||||
|
if sn <= 0 {
|
||||||
|
goto lastLiterals
|
||||||
}
|
}
|
||||||
var si int
|
|
||||||
|
|
||||||
// Fast scan strategy: the hash table only stores the last 4 bytes sequences.
|
// Fast scan strategy: the hash table only stores the last 4 bytes sequences.
|
||||||
// const accInit = 1 << skipStrength
|
|
||||||
|
|
||||||
anchor := si // Position of the current literals.
|
|
||||||
// acc := accInit // Variable step: improves performance on non-compressible data.
|
|
||||||
|
|
||||||
for si < sn {
|
for si < sn {
|
||||||
// Hash the next 4 bytes (sequence)...
|
// Hash the next 6 bytes (sequence)...
|
||||||
match := binary.LittleEndian.Uint32(src[si:])
|
match := binary.LittleEndian.Uint64(src[si:])
|
||||||
h := blockHash(match)
|
h := blockHash(match)
|
||||||
|
h2 := blockHash(match >> 8)
|
||||||
|
|
||||||
|
// We check a match at s, s+1 and s+2 and pick the first one we get.
|
||||||
|
// Checking 3 only requires us to load the source one.
|
||||||
ref := hashTable[h]
|
ref := hashTable[h]
|
||||||
|
ref2 := hashTable[h2]
|
||||||
hashTable[h] = si
|
hashTable[h] = si
|
||||||
if ref >= sn { // Invalid reference (dirty hashtable).
|
hashTable[h2] = si + 1
|
||||||
si++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
offset := si - ref
|
offset := si - ref
|
||||||
|
|
||||||
|
// If offset <= 0 we got an old entry in the hash table.
|
||||||
if offset <= 0 || offset >= winSize || // Out of window.
|
if offset <= 0 || offset >= winSize || // Out of window.
|
||||||
match != binary.LittleEndian.Uint32(src[ref:]) { // Hash collision on different matches.
|
uint32(match) != binary.LittleEndian.Uint32(src[ref:]) { // Hash collision on different matches.
|
||||||
// si += acc >> skipStrength
|
// No match. Start calculating another hash.
|
||||||
// acc++
|
// The processor can usually do this out-of-order.
|
||||||
si++
|
h = blockHash(match >> 16)
|
||||||
continue
|
ref = hashTable[h]
|
||||||
|
|
||||||
|
// Check the second match at si+1
|
||||||
|
si += 1
|
||||||
|
offset = si - ref2
|
||||||
|
|
||||||
|
if offset <= 0 || offset >= winSize ||
|
||||||
|
uint32(match>>8) != binary.LittleEndian.Uint32(src[ref2:]) {
|
||||||
|
// No match. Check the third match at si+2
|
||||||
|
si += 1
|
||||||
|
offset = si - ref
|
||||||
|
hashTable[h] = si
|
||||||
|
|
||||||
|
if offset <= 0 || offset >= winSize ||
|
||||||
|
uint32(match>>16) != binary.LittleEndian.Uint32(src[ref:]) {
|
||||||
|
// Skip one extra byte (at si+3) before we check 3 matches again.
|
||||||
|
si += 2 + (si-anchor)>>adaptSkipLog
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match found.
|
// Match found.
|
||||||
// acc = accInit
|
|
||||||
lLen := si - anchor // Literal length.
|
lLen := si - anchor // Literal length.
|
||||||
|
// We already matched 4 bytes.
|
||||||
|
mLen := 4
|
||||||
|
|
||||||
// Encode match length part 1.
|
// Extend backwards if we can, reducing literals.
|
||||||
si += minMatch
|
tOff := si - offset - 1
|
||||||
mLen := si // Match length has minMatch already.
|
for lLen > 0 && tOff >= 0 && src[si-1] == src[tOff] {
|
||||||
// Find the longest match, first looking by batches of 8 bytes.
|
si--
|
||||||
for si < sn && binary.LittleEndian.Uint64(src[si:]) == binary.LittleEndian.Uint64(src[si-offset:]) {
|
tOff--
|
||||||
si += 8
|
lLen--
|
||||||
|
mLen++
|
||||||
}
|
}
|
||||||
// Then byte by byte.
|
|
||||||
for si < sn && src[si] == src[si-offset] {
|
// Add the match length, so we continue search at the end.
|
||||||
si++
|
// Use mLen to store the offset base.
|
||||||
|
si, mLen = si+mLen, si+minMatch
|
||||||
|
|
||||||
|
// Find the longest match by looking by batches of 8 bytes.
|
||||||
|
for si+8 < sn {
|
||||||
|
x := binary.LittleEndian.Uint64(src[si:]) ^ binary.LittleEndian.Uint64(src[si-offset:])
|
||||||
|
if x == 0 {
|
||||||
|
si += 8
|
||||||
|
} else {
|
||||||
|
// Stop is first non-zero byte.
|
||||||
|
si += bits.TrailingZeros64(x) >> 3
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLen = si - mLen
|
mLen = si - mLen
|
||||||
@ -186,7 +169,7 @@ func CompressBlock(src, dst []byte, hashTable []int) (di int, err error) {
|
|||||||
di++
|
di++
|
||||||
|
|
||||||
// Literals.
|
// Literals.
|
||||||
copy(dst[di:], src[anchor:anchor+lLen])
|
copy(dst[di:di+lLen], src[anchor:anchor+lLen])
|
||||||
di += lLen + 2
|
di += lLen + 2
|
||||||
anchor = si
|
anchor = si
|
||||||
|
|
||||||
@ -203,9 +186,17 @@ func CompressBlock(src, dst []byte, hashTable []int) (di int, err error) {
|
|||||||
dst[di] = byte(mLen)
|
dst[di] = byte(mLen)
|
||||||
di++
|
di++
|
||||||
}
|
}
|
||||||
|
// Check if we can load next values.
|
||||||
|
if si >= sn {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Hash match end-2
|
||||||
|
h = blockHash(binary.LittleEndian.Uint64(src[si-2:]))
|
||||||
|
hashTable[h] = si - 2
|
||||||
}
|
}
|
||||||
|
|
||||||
if anchor == 0 {
|
lastLiterals:
|
||||||
|
if isNotCompressible && anchor == 0 {
|
||||||
// Incompressible.
|
// Incompressible.
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
@ -226,48 +217,68 @@ func CompressBlock(src, dst []byte, hashTable []int) (di int, err error) {
|
|||||||
di++
|
di++
|
||||||
|
|
||||||
// Write the last literals.
|
// Write the last literals.
|
||||||
if di >= anchor {
|
if isNotCompressible && di >= anchor {
|
||||||
// Incompressible.
|
// Incompressible.
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
di += copy(dst[di:], src[anchor:])
|
di += copy(dst[di:di+len(src)-anchor], src[anchor:])
|
||||||
return di, nil
|
return di, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pool of hash tables for CompressBlock.
|
||||||
|
var htPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return new([htSize]int)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// blockHash hashes 4 bytes into a value < winSize.
|
||||||
|
func blockHashHC(x uint32) uint32 {
|
||||||
|
const hasher uint32 = 2654435761 // Knuth multiplicative hash.
|
||||||
|
return x * hasher >> (32 - winSizeLog)
|
||||||
|
}
|
||||||
|
|
||||||
// CompressBlockHC compresses the source buffer src into the destination dst
|
// CompressBlockHC compresses the source buffer src into the destination dst
|
||||||
// with max search depth (use 0 or negative value for no max).
|
// with max search depth (use 0 or negative value for no max).
|
||||||
//
|
//
|
||||||
// CompressBlockHC compression ratio is better than CompressBlock but it is also slower.
|
// CompressBlockHC compression ratio is better than CompressBlock but it is also slower.
|
||||||
//
|
//
|
||||||
// The size of the compressed data is returned. If it is 0 and no error, then the data is not compressible.
|
// The size of the compressed data is returned.
|
||||||
|
//
|
||||||
|
// If the destination buffer size is lower than CompressBlockBound and
|
||||||
|
// the compressed size is 0 and no error, then the data is incompressible.
|
||||||
//
|
//
|
||||||
// An error is returned if the destination buffer is too small.
|
// An error is returned if the destination buffer is too small.
|
||||||
func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
func CompressBlockHC(src, dst []byte, depth int) (_ int, err error) {
|
||||||
defer func() {
|
defer recoverBlock(&err)
|
||||||
if recover() != nil {
|
|
||||||
err = ErrInvalidSourceShortBuffer
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
sn, dn := len(src)-mfLimit, len(dst)
|
// Return 0, nil only if the destination buffer size is < CompressBlockBound.
|
||||||
if sn <= 0 || dn == 0 {
|
isNotCompressible := len(dst) < CompressBlockBound(len(src))
|
||||||
return 0, nil
|
|
||||||
}
|
// adaptSkipLog sets how quickly the compressor begins skipping blocks when data is incompressible.
|
||||||
var si int
|
// This significantly speeds up incompressible data and usually has very small impact on compression.
|
||||||
|
// bytes to skip = 1 + (bytes since last match >> adaptSkipLog)
|
||||||
|
const adaptSkipLog = 7
|
||||||
|
|
||||||
|
var si, di, anchor int
|
||||||
|
|
||||||
// hashTable: stores the last position found for a given hash
|
// hashTable: stores the last position found for a given hash
|
||||||
// chaingTable: stores previous positions for a given hash
|
// chainTable: stores previous positions for a given hash
|
||||||
var hashTable, chainTable [winSize]int
|
var hashTable, chainTable [winSize]int
|
||||||
|
|
||||||
if depth <= 0 {
|
if depth <= 0 {
|
||||||
depth = winSize
|
depth = winSize
|
||||||
}
|
}
|
||||||
|
|
||||||
anchor := si
|
sn := len(src) - mfLimit
|
||||||
|
if sn <= 0 {
|
||||||
|
goto lastLiterals
|
||||||
|
}
|
||||||
|
|
||||||
for si < sn {
|
for si < sn {
|
||||||
// Hash the next 4 bytes (sequence).
|
// Hash the next 4 bytes (sequence).
|
||||||
match := binary.LittleEndian.Uint32(src[si:])
|
match := binary.LittleEndian.Uint32(src[si:])
|
||||||
h := blockHash(match)
|
h := blockHashHC(match)
|
||||||
|
|
||||||
// Follow the chain until out of window and give the longest match.
|
// Follow the chain until out of window and give the longest match.
|
||||||
mLen := 0
|
mLen := 0
|
||||||
@ -280,13 +291,17 @@ func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
|||||||
}
|
}
|
||||||
ml := 0
|
ml := 0
|
||||||
// Compare the current position with a previous with the same hash.
|
// Compare the current position with a previous with the same hash.
|
||||||
for ml < sn-si && binary.LittleEndian.Uint64(src[next+ml:]) == binary.LittleEndian.Uint64(src[si+ml:]) {
|
for ml < sn-si {
|
||||||
ml += 8
|
x := binary.LittleEndian.Uint64(src[next+ml:]) ^ binary.LittleEndian.Uint64(src[si+ml:])
|
||||||
|
if x == 0 {
|
||||||
|
ml += 8
|
||||||
|
} else {
|
||||||
|
// Stop is first non-zero byte.
|
||||||
|
ml += bits.TrailingZeros64(x) >> 3
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for ml < sn-si && src[next+ml] == src[si+ml] {
|
if ml < minMatch || ml <= mLen {
|
||||||
ml++
|
|
||||||
}
|
|
||||||
if ml+1 < minMatch || ml <= mLen {
|
|
||||||
// Match too small (<minMath) or smaller than the current match.
|
// Match too small (<minMath) or smaller than the current match.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -301,7 +316,7 @@ func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
|||||||
|
|
||||||
// No match found.
|
// No match found.
|
||||||
if mLen == 0 {
|
if mLen == 0 {
|
||||||
si++
|
si += 1 + (si-anchor)>>adaptSkipLog
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +330,7 @@ func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
|||||||
for si, ml := winStart, si+mLen; si < ml; {
|
for si, ml := winStart, si+mLen; si < ml; {
|
||||||
match >>= 8
|
match >>= 8
|
||||||
match |= uint32(src[si+3]) << 24
|
match |= uint32(src[si+3]) << 24
|
||||||
h := blockHash(match)
|
h := blockHashHC(match)
|
||||||
chainTable[si&winMask] = hashTable[h]
|
chainTable[si&winMask] = hashTable[h]
|
||||||
hashTable[h] = si
|
hashTable[h] = si
|
||||||
si++
|
si++
|
||||||
@ -347,7 +362,7 @@ func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
|||||||
di++
|
di++
|
||||||
|
|
||||||
// Literals.
|
// Literals.
|
||||||
copy(dst[di:], src[anchor:anchor+lLen])
|
copy(dst[di:di+lLen], src[anchor:anchor+lLen])
|
||||||
di += lLen
|
di += lLen
|
||||||
anchor = si
|
anchor = si
|
||||||
|
|
||||||
@ -366,12 +381,13 @@ func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if anchor == 0 {
|
if isNotCompressible && anchor == 0 {
|
||||||
// Incompressible.
|
// Incompressible.
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last literals.
|
// Last literals.
|
||||||
|
lastLiterals:
|
||||||
lLen := len(src) - anchor
|
lLen := len(src) - anchor
|
||||||
if lLen < 0xF {
|
if lLen < 0xF {
|
||||||
dst[di] = byte(lLen << 4)
|
dst[di] = byte(lLen << 4)
|
||||||
@ -388,10 +404,10 @@ func CompressBlockHC(src, dst []byte, depth int) (di int, err error) {
|
|||||||
di++
|
di++
|
||||||
|
|
||||||
// Write the last literals.
|
// Write the last literals.
|
||||||
if di >= anchor {
|
if isNotCompressible && di >= anchor {
|
||||||
// Incompressible.
|
// Incompressible.
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
di += copy(dst[di:], src[anchor:])
|
di += copy(dst[di:di+len(src)-anchor], src[anchor:])
|
||||||
return di, nil
|
return di, nil
|
||||||
}
|
}
|
||||||
|
8
vendor/github.com/pierrec/lz4/decode_amd64.go
generated
vendored
Normal file
8
vendor/github.com/pierrec/lz4/decode_amd64.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !noasm
|
||||||
|
|
||||||
|
package lz4
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func decodeBlock(dst, src []byte) int
|
375
vendor/github.com/pierrec/lz4/decode_amd64.s
generated
vendored
Normal file
375
vendor/github.com/pierrec/lz4/decode_amd64.s
generated
vendored
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !noasm
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// AX scratch
|
||||||
|
// BX scratch
|
||||||
|
// CX scratch
|
||||||
|
// DX token
|
||||||
|
//
|
||||||
|
// DI &dst
|
||||||
|
// SI &src
|
||||||
|
// R8 &dst + len(dst)
|
||||||
|
// R9 &src + len(src)
|
||||||
|
// R11 &dst
|
||||||
|
// R12 short output end
|
||||||
|
// R13 short input end
|
||||||
|
// func decodeBlock(dst, src []byte) int
|
||||||
|
// using 50 bytes of stack currently
|
||||||
|
TEXT ·decodeBlock(SB), NOSPLIT, $64-56
|
||||||
|
MOVQ dst_base+0(FP), DI
|
||||||
|
MOVQ DI, R11
|
||||||
|
MOVQ dst_len+8(FP), R8
|
||||||
|
ADDQ DI, R8
|
||||||
|
|
||||||
|
MOVQ src_base+24(FP), SI
|
||||||
|
MOVQ src_len+32(FP), R9
|
||||||
|
ADDQ SI, R9
|
||||||
|
|
||||||
|
// shortcut ends
|
||||||
|
// short output end
|
||||||
|
MOVQ R8, R12
|
||||||
|
SUBQ $32, R12
|
||||||
|
// short input end
|
||||||
|
MOVQ R9, R13
|
||||||
|
SUBQ $16, R13
|
||||||
|
|
||||||
|
loop:
|
||||||
|
// for si < len(src)
|
||||||
|
CMPQ SI, R9
|
||||||
|
JGE end
|
||||||
|
|
||||||
|
// token := uint32(src[si])
|
||||||
|
MOVBQZX (SI), DX
|
||||||
|
INCQ SI
|
||||||
|
|
||||||
|
// lit_len = token >> 4
|
||||||
|
// if lit_len > 0
|
||||||
|
// CX = lit_len
|
||||||
|
MOVQ DX, CX
|
||||||
|
SHRQ $4, CX
|
||||||
|
|
||||||
|
// if lit_len != 0xF
|
||||||
|
CMPQ CX, $0xF
|
||||||
|
JEQ lit_len_loop_pre
|
||||||
|
CMPQ DI, R12
|
||||||
|
JGE lit_len_loop_pre
|
||||||
|
CMPQ SI, R13
|
||||||
|
JGE lit_len_loop_pre
|
||||||
|
|
||||||
|
// copy shortcut
|
||||||
|
|
||||||
|
// A two-stage shortcut for the most common case:
|
||||||
|
// 1) If the literal length is 0..14, and there is enough space,
|
||||||
|
// enter the shortcut and copy 16 bytes on behalf of the literals
|
||||||
|
// (in the fast mode, only 8 bytes can be safely copied this way).
|
||||||
|
// 2) Further if the match length is 4..18, copy 18 bytes in a similar
|
||||||
|
// manner; but we ensure that there's enough space in the output for
|
||||||
|
// those 18 bytes earlier, upon entering the shortcut (in other words,
|
||||||
|
// there is a combined check for both stages).
|
||||||
|
|
||||||
|
// copy literal
|
||||||
|
MOVOU (SI), X0
|
||||||
|
MOVOU X0, (DI)
|
||||||
|
ADDQ CX, DI
|
||||||
|
ADDQ CX, SI
|
||||||
|
|
||||||
|
MOVQ DX, CX
|
||||||
|
ANDQ $0xF, CX
|
||||||
|
|
||||||
|
// The second stage: prepare for match copying, decode full info.
|
||||||
|
// If it doesn't work out, the info won't be wasted.
|
||||||
|
// offset := uint16(data[:2])
|
||||||
|
MOVWQZX (SI), DX
|
||||||
|
ADDQ $2, SI
|
||||||
|
|
||||||
|
MOVQ DI, AX
|
||||||
|
SUBQ DX, AX
|
||||||
|
CMPQ AX, DI
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
// if we can't do the second stage then jump straight to read the
|
||||||
|
// match length, we already have the offset.
|
||||||
|
CMPQ CX, $0xF
|
||||||
|
JEQ match_len_loop_pre
|
||||||
|
CMPQ DX, $8
|
||||||
|
JLT match_len_loop_pre
|
||||||
|
CMPQ AX, R11
|
||||||
|
JLT err_short_buf
|
||||||
|
|
||||||
|
// memcpy(op + 0, match + 0, 8);
|
||||||
|
MOVQ (AX), BX
|
||||||
|
MOVQ BX, (DI)
|
||||||
|
// memcpy(op + 8, match + 8, 8);
|
||||||
|
MOVQ 8(AX), BX
|
||||||
|
MOVQ BX, 8(DI)
|
||||||
|
// memcpy(op +16, match +16, 2);
|
||||||
|
MOVW 16(AX), BX
|
||||||
|
MOVW BX, 16(DI)
|
||||||
|
|
||||||
|
ADDQ $4, DI // minmatch
|
||||||
|
ADDQ CX, DI
|
||||||
|
|
||||||
|
// shortcut complete, load next token
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
lit_len_loop_pre:
|
||||||
|
// if lit_len > 0
|
||||||
|
CMPQ CX, $0
|
||||||
|
JEQ offset
|
||||||
|
CMPQ CX, $0xF
|
||||||
|
JNE copy_literal
|
||||||
|
|
||||||
|
lit_len_loop:
|
||||||
|
// for src[si] == 0xFF
|
||||||
|
CMPB (SI), $0xFF
|
||||||
|
JNE lit_len_finalise
|
||||||
|
|
||||||
|
// bounds check src[si+1]
|
||||||
|
MOVQ SI, AX
|
||||||
|
ADDQ $1, AX
|
||||||
|
CMPQ AX, R9
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
// lit_len += 0xFF
|
||||||
|
ADDQ $0xFF, CX
|
||||||
|
INCQ SI
|
||||||
|
JMP lit_len_loop
|
||||||
|
|
||||||
|
lit_len_finalise:
|
||||||
|
// lit_len += int(src[si])
|
||||||
|
// si++
|
||||||
|
MOVBQZX (SI), AX
|
||||||
|
ADDQ AX, CX
|
||||||
|
INCQ SI
|
||||||
|
|
||||||
|
copy_literal:
|
||||||
|
// bounds check src and dst
|
||||||
|
MOVQ SI, AX
|
||||||
|
ADDQ CX, AX
|
||||||
|
CMPQ AX, R9
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
MOVQ DI, AX
|
||||||
|
ADDQ CX, AX
|
||||||
|
CMPQ AX, R8
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
// whats a good cut off to call memmove?
|
||||||
|
CMPQ CX, $16
|
||||||
|
JGT memmove_lit
|
||||||
|
|
||||||
|
// if len(dst[di:]) < 16
|
||||||
|
MOVQ R8, AX
|
||||||
|
SUBQ DI, AX
|
||||||
|
CMPQ AX, $16
|
||||||
|
JLT memmove_lit
|
||||||
|
|
||||||
|
// if len(src[si:]) < 16
|
||||||
|
MOVQ R9, AX
|
||||||
|
SUBQ SI, AX
|
||||||
|
CMPQ AX, $16
|
||||||
|
JLT memmove_lit
|
||||||
|
|
||||||
|
MOVOU (SI), X0
|
||||||
|
MOVOU X0, (DI)
|
||||||
|
|
||||||
|
JMP finish_lit_copy
|
||||||
|
|
||||||
|
memmove_lit:
|
||||||
|
// memmove(to, from, len)
|
||||||
|
MOVQ DI, 0(SP)
|
||||||
|
MOVQ SI, 8(SP)
|
||||||
|
MOVQ CX, 16(SP)
|
||||||
|
// spill
|
||||||
|
MOVQ DI, 24(SP)
|
||||||
|
MOVQ SI, 32(SP)
|
||||||
|
MOVQ CX, 40(SP) // need len to inc SI, DI after
|
||||||
|
MOVB DX, 48(SP)
|
||||||
|
CALL runtime·memmove(SB)
|
||||||
|
|
||||||
|
// restore registers
|
||||||
|
MOVQ 24(SP), DI
|
||||||
|
MOVQ 32(SP), SI
|
||||||
|
MOVQ 40(SP), CX
|
||||||
|
MOVB 48(SP), DX
|
||||||
|
|
||||||
|
// recalc initial values
|
||||||
|
MOVQ dst_base+0(FP), R8
|
||||||
|
MOVQ R8, R11
|
||||||
|
ADDQ dst_len+8(FP), R8
|
||||||
|
MOVQ src_base+24(FP), R9
|
||||||
|
ADDQ src_len+32(FP), R9
|
||||||
|
MOVQ R8, R12
|
||||||
|
SUBQ $32, R12
|
||||||
|
MOVQ R9, R13
|
||||||
|
SUBQ $16, R13
|
||||||
|
|
||||||
|
finish_lit_copy:
|
||||||
|
ADDQ CX, SI
|
||||||
|
ADDQ CX, DI
|
||||||
|
|
||||||
|
CMPQ SI, R9
|
||||||
|
JGE end
|
||||||
|
|
||||||
|
offset:
|
||||||
|
// CX := mLen
|
||||||
|
// free up DX to use for offset
|
||||||
|
MOVQ DX, CX
|
||||||
|
|
||||||
|
MOVQ SI, AX
|
||||||
|
ADDQ $2, AX
|
||||||
|
CMPQ AX, R9
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
// offset
|
||||||
|
// DX := int(src[si]) | int(src[si+1])<<8
|
||||||
|
MOVWQZX (SI), DX
|
||||||
|
ADDQ $2, SI
|
||||||
|
|
||||||
|
// 0 offset is invalid
|
||||||
|
CMPQ DX, $0
|
||||||
|
JEQ err_corrupt
|
||||||
|
|
||||||
|
ANDB $0xF, CX
|
||||||
|
|
||||||
|
match_len_loop_pre:
|
||||||
|
// if mlen != 0xF
|
||||||
|
CMPB CX, $0xF
|
||||||
|
JNE copy_match
|
||||||
|
|
||||||
|
match_len_loop:
|
||||||
|
// for src[si] == 0xFF
|
||||||
|
// lit_len += 0xFF
|
||||||
|
CMPB (SI), $0xFF
|
||||||
|
JNE match_len_finalise
|
||||||
|
|
||||||
|
// bounds check src[si+1]
|
||||||
|
MOVQ SI, AX
|
||||||
|
ADDQ $1, AX
|
||||||
|
CMPQ AX, R9
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
ADDQ $0xFF, CX
|
||||||
|
INCQ SI
|
||||||
|
JMP match_len_loop
|
||||||
|
|
||||||
|
match_len_finalise:
|
||||||
|
// lit_len += int(src[si])
|
||||||
|
// si++
|
||||||
|
MOVBQZX (SI), AX
|
||||||
|
ADDQ AX, CX
|
||||||
|
INCQ SI
|
||||||
|
|
||||||
|
copy_match:
|
||||||
|
// mLen += minMatch
|
||||||
|
ADDQ $4, CX
|
||||||
|
|
||||||
|
// check we have match_len bytes left in dst
|
||||||
|
// di+match_len < len(dst)
|
||||||
|
MOVQ DI, AX
|
||||||
|
ADDQ CX, AX
|
||||||
|
CMPQ AX, R8
|
||||||
|
JGT err_short_buf
|
||||||
|
|
||||||
|
// DX = offset
|
||||||
|
// CX = match_len
|
||||||
|
// BX = &dst + (di - offset)
|
||||||
|
MOVQ DI, BX
|
||||||
|
SUBQ DX, BX
|
||||||
|
|
||||||
|
// check BX is within dst
|
||||||
|
// if BX < &dst
|
||||||
|
CMPQ BX, R11
|
||||||
|
JLT err_short_buf
|
||||||
|
|
||||||
|
// if offset + match_len < di
|
||||||
|
MOVQ BX, AX
|
||||||
|
ADDQ CX, AX
|
||||||
|
CMPQ DI, AX
|
||||||
|
JGT copy_interior_match
|
||||||
|
|
||||||
|
// AX := len(dst[:di])
|
||||||
|
// MOVQ DI, AX
|
||||||
|
// SUBQ R11, AX
|
||||||
|
|
||||||
|
// copy 16 bytes at a time
|
||||||
|
// if di-offset < 16 copy 16-(di-offset) bytes to di
|
||||||
|
// then do the remaining
|
||||||
|
|
||||||
|
copy_match_loop:
|
||||||
|
// for match_len >= 0
|
||||||
|
// dst[di] = dst[i]
|
||||||
|
// di++
|
||||||
|
// i++
|
||||||
|
MOVB (BX), AX
|
||||||
|
MOVB AX, (DI)
|
||||||
|
INCQ DI
|
||||||
|
INCQ BX
|
||||||
|
DECQ CX
|
||||||
|
|
||||||
|
CMPQ CX, $0
|
||||||
|
JGT copy_match_loop
|
||||||
|
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
copy_interior_match:
|
||||||
|
CMPQ CX, $16
|
||||||
|
JGT memmove_match
|
||||||
|
|
||||||
|
// if len(dst[di:]) < 16
|
||||||
|
MOVQ R8, AX
|
||||||
|
SUBQ DI, AX
|
||||||
|
CMPQ AX, $16
|
||||||
|
JLT memmove_match
|
||||||
|
|
||||||
|
MOVOU (BX), X0
|
||||||
|
MOVOU X0, (DI)
|
||||||
|
|
||||||
|
ADDQ CX, DI
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
memmove_match:
|
||||||
|
// memmove(to, from, len)
|
||||||
|
MOVQ DI, 0(SP)
|
||||||
|
MOVQ BX, 8(SP)
|
||||||
|
MOVQ CX, 16(SP)
|
||||||
|
// spill
|
||||||
|
MOVQ DI, 24(SP)
|
||||||
|
MOVQ SI, 32(SP)
|
||||||
|
MOVQ CX, 40(SP) // need len to inc SI, DI after
|
||||||
|
CALL runtime·memmove(SB)
|
||||||
|
|
||||||
|
// restore registers
|
||||||
|
MOVQ 24(SP), DI
|
||||||
|
MOVQ 32(SP), SI
|
||||||
|
MOVQ 40(SP), CX
|
||||||
|
|
||||||
|
// recalc initial values
|
||||||
|
MOVQ dst_base+0(FP), R8
|
||||||
|
MOVQ R8, R11 // TODO: make these sensible numbers
|
||||||
|
ADDQ dst_len+8(FP), R8
|
||||||
|
MOVQ src_base+24(FP), R9
|
||||||
|
ADDQ src_len+32(FP), R9
|
||||||
|
MOVQ R8, R12
|
||||||
|
SUBQ $32, R12
|
||||||
|
MOVQ R9, R13
|
||||||
|
SUBQ $16, R13
|
||||||
|
|
||||||
|
ADDQ CX, DI
|
||||||
|
JMP loop
|
||||||
|
|
||||||
|
err_corrupt:
|
||||||
|
MOVQ $-1, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
err_short_buf:
|
||||||
|
MOVQ $-2, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
end:
|
||||||
|
SUBQ R11, DI
|
||||||
|
MOVQ DI, ret+48(FP)
|
||||||
|
RET
|
98
vendor/github.com/pierrec/lz4/decode_other.go
generated
vendored
Normal file
98
vendor/github.com/pierrec/lz4/decode_other.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// +build !amd64 appengine !gc noasm
|
||||||
|
|
||||||
|
package lz4
|
||||||
|
|
||||||
|
func decodeBlock(dst, src []byte) (ret int) {
|
||||||
|
const hasError = -2
|
||||||
|
defer func() {
|
||||||
|
if recover() != nil {
|
||||||
|
ret = hasError
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var si, di int
|
||||||
|
for {
|
||||||
|
// Literals and match lengths (token).
|
||||||
|
b := int(src[si])
|
||||||
|
si++
|
||||||
|
|
||||||
|
// Literals.
|
||||||
|
if lLen := b >> 4; lLen > 0 {
|
||||||
|
switch {
|
||||||
|
case lLen < 0xF && si+16 < len(src):
|
||||||
|
// Shortcut 1
|
||||||
|
// if we have enough room in src and dst, and the literals length
|
||||||
|
// is small enough (0..14) then copy all 16 bytes, even if not all
|
||||||
|
// are part of the literals.
|
||||||
|
copy(dst[di:], src[si:si+16])
|
||||||
|
si += lLen
|
||||||
|
di += lLen
|
||||||
|
if mLen := b & 0xF; mLen < 0xF {
|
||||||
|
// Shortcut 2
|
||||||
|
// if the match length (4..18) fits within the literals, then copy
|
||||||
|
// all 18 bytes, even if not all are part of the literals.
|
||||||
|
mLen += 4
|
||||||
|
if offset := int(src[si]) | int(src[si+1])<<8; mLen <= offset {
|
||||||
|
i := di - offset
|
||||||
|
end := i + 18
|
||||||
|
if end > len(dst) {
|
||||||
|
// The remaining buffer may not hold 18 bytes.
|
||||||
|
// See https://github.com/pierrec/lz4/issues/51.
|
||||||
|
end = len(dst)
|
||||||
|
}
|
||||||
|
copy(dst[di:], dst[i:end])
|
||||||
|
si += 2
|
||||||
|
di += mLen
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case lLen == 0xF:
|
||||||
|
for src[si] == 0xFF {
|
||||||
|
lLen += 0xFF
|
||||||
|
si++
|
||||||
|
}
|
||||||
|
lLen += int(src[si])
|
||||||
|
si++
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
copy(dst[di:di+lLen], src[si:si+lLen])
|
||||||
|
si += lLen
|
||||||
|
di += lLen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if si >= len(src) {
|
||||||
|
return di
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := int(src[si]) | int(src[si+1])<<8
|
||||||
|
if offset == 0 {
|
||||||
|
return hasError
|
||||||
|
}
|
||||||
|
si += 2
|
||||||
|
|
||||||
|
// Match.
|
||||||
|
mLen := b & 0xF
|
||||||
|
if mLen == 0xF {
|
||||||
|
for src[si] == 0xFF {
|
||||||
|
mLen += 0xFF
|
||||||
|
si++
|
||||||
|
}
|
||||||
|
mLen += int(src[si])
|
||||||
|
si++
|
||||||
|
}
|
||||||
|
mLen += minMatch
|
||||||
|
|
||||||
|
// Copy the match.
|
||||||
|
expanded := dst[di-offset:]
|
||||||
|
if mLen > offset {
|
||||||
|
// Efficiently copy the match dst[di-offset:di] into the dst slice.
|
||||||
|
bytesToCopy := offset * (mLen / offset)
|
||||||
|
for n := offset; n <= bytesToCopy+offset; n *= 2 {
|
||||||
|
copy(expanded[n:], expanded[:n])
|
||||||
|
}
|
||||||
|
di += bytesToCopy
|
||||||
|
mLen -= bytesToCopy
|
||||||
|
}
|
||||||
|
di += copy(dst[di:di+mLen], expanded[:mLen])
|
||||||
|
}
|
||||||
|
}
|
30
vendor/github.com/pierrec/lz4/errors.go
generated
vendored
Normal file
30
vendor/github.com/pierrec/lz4/errors.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package lz4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
rdebug "runtime/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrInvalidSourceShortBuffer is returned by UncompressBlock or CompressBLock when a compressed
|
||||||
|
// block is corrupted or the destination buffer is not large enough for the uncompressed data.
|
||||||
|
ErrInvalidSourceShortBuffer = errors.New("lz4: invalid source or destination buffer too short")
|
||||||
|
// ErrInvalid is returned when reading an invalid LZ4 archive.
|
||||||
|
ErrInvalid = errors.New("lz4: bad magic number")
|
||||||
|
// ErrBlockDependency is returned when attempting to decompress an archive created with block dependency.
|
||||||
|
ErrBlockDependency = errors.New("lz4: block dependency not supported")
|
||||||
|
// ErrUnsupportedSeek is returned when attempting to Seek any way but forward from the current position.
|
||||||
|
ErrUnsupportedSeek = errors.New("lz4: can only seek forward from io.SeekCurrent")
|
||||||
|
)
|
||||||
|
|
||||||
|
func recoverBlock(e *error) {
|
||||||
|
if r := recover(); r != nil && *e == nil {
|
||||||
|
if debugFlag {
|
||||||
|
fmt.Fprintln(os.Stderr, r)
|
||||||
|
rdebug.PrintStack()
|
||||||
|
}
|
||||||
|
*e = ErrInvalidSourceShortBuffer
|
||||||
|
}
|
||||||
|
}
|
87
vendor/github.com/pierrec/lz4/internal/xxh32/xxh32zero.go
generated
vendored
87
vendor/github.com/pierrec/lz4/internal/xxh32/xxh32zero.go
generated
vendored
@ -7,14 +7,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
prime32_1 uint32 = 2654435761
|
prime1 uint32 = 2654435761
|
||||||
prime32_2 uint32 = 2246822519
|
prime2 uint32 = 2246822519
|
||||||
prime32_3 uint32 = 3266489917
|
prime3 uint32 = 3266489917
|
||||||
prime32_4 uint32 = 668265263
|
prime4 uint32 = 668265263
|
||||||
prime32_5 uint32 = 374761393
|
prime5 uint32 = 374761393
|
||||||
|
|
||||||
prime32_1plus2 uint32 = 606290984
|
primeMask = 0xFFFFFFFF
|
||||||
prime32_minus1 uint32 = 1640531535
|
prime1plus2 = uint32((uint64(prime1) + uint64(prime2)) & primeMask) // 606290984
|
||||||
|
prime1minus = uint32((-int64(prime1)) & primeMask) // 1640531535
|
||||||
)
|
)
|
||||||
|
|
||||||
// XXHZero represents an xxhash32 object with seed 0.
|
// XXHZero represents an xxhash32 object with seed 0.
|
||||||
@ -37,10 +38,10 @@ func (xxh XXHZero) Sum(b []byte) []byte {
|
|||||||
|
|
||||||
// Reset resets the Hash to its initial state.
|
// Reset resets the Hash to its initial state.
|
||||||
func (xxh *XXHZero) Reset() {
|
func (xxh *XXHZero) Reset() {
|
||||||
xxh.v1 = prime32_1plus2
|
xxh.v1 = prime1plus2
|
||||||
xxh.v2 = prime32_2
|
xxh.v2 = prime2
|
||||||
xxh.v3 = 0
|
xxh.v3 = 0
|
||||||
xxh.v4 = prime32_minus1
|
xxh.v4 = prime1minus
|
||||||
xxh.totalLen = 0
|
xxh.totalLen = 0
|
||||||
xxh.bufused = 0
|
xxh.bufused = 0
|
||||||
}
|
}
|
||||||
@ -83,20 +84,20 @@ func (xxh *XXHZero) Write(input []byte) (int, error) {
|
|||||||
|
|
||||||
// fast rotl(13)
|
// fast rotl(13)
|
||||||
buf := xxh.buf[:16] // BCE hint.
|
buf := xxh.buf[:16] // BCE hint.
|
||||||
v1 = rol13(v1+binary.LittleEndian.Uint32(buf[:])*prime32_2) * prime32_1
|
v1 = rol13(v1+binary.LittleEndian.Uint32(buf[:])*prime2) * prime1
|
||||||
v2 = rol13(v2+binary.LittleEndian.Uint32(buf[4:])*prime32_2) * prime32_1
|
v2 = rol13(v2+binary.LittleEndian.Uint32(buf[4:])*prime2) * prime1
|
||||||
v3 = rol13(v3+binary.LittleEndian.Uint32(buf[8:])*prime32_2) * prime32_1
|
v3 = rol13(v3+binary.LittleEndian.Uint32(buf[8:])*prime2) * prime1
|
||||||
v4 = rol13(v4+binary.LittleEndian.Uint32(buf[12:])*prime32_2) * prime32_1
|
v4 = rol13(v4+binary.LittleEndian.Uint32(buf[12:])*prime2) * prime1
|
||||||
p = r
|
p = r
|
||||||
xxh.bufused = 0
|
xxh.bufused = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
for n := n - 16; p <= n; p += 16 {
|
for n := n - 16; p <= n; p += 16 {
|
||||||
sub := input[p:][:16] //BCE hint for compiler
|
sub := input[p:][:16] //BCE hint for compiler
|
||||||
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime32_2) * prime32_1
|
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime2) * prime1
|
||||||
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime32_2) * prime32_1
|
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime2) * prime1
|
||||||
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime32_2) * prime32_1
|
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime2) * prime1
|
||||||
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime32_2) * prime32_1
|
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime2) * prime1
|
||||||
}
|
}
|
||||||
xxh.v1, xxh.v2, xxh.v3, xxh.v4 = v1, v2, v3, v4
|
xxh.v1, xxh.v2, xxh.v3, xxh.v4 = v1, v2, v3, v4
|
||||||
|
|
||||||
@ -112,25 +113,25 @@ func (xxh *XXHZero) Sum32() uint32 {
|
|||||||
if h32 >= 16 {
|
if h32 >= 16 {
|
||||||
h32 += rol1(xxh.v1) + rol7(xxh.v2) + rol12(xxh.v3) + rol18(xxh.v4)
|
h32 += rol1(xxh.v1) + rol7(xxh.v2) + rol12(xxh.v3) + rol18(xxh.v4)
|
||||||
} else {
|
} else {
|
||||||
h32 += prime32_5
|
h32 += prime5
|
||||||
}
|
}
|
||||||
|
|
||||||
p := 0
|
p := 0
|
||||||
n := xxh.bufused
|
n := xxh.bufused
|
||||||
buf := xxh.buf
|
buf := xxh.buf
|
||||||
for n := n - 4; p <= n; p += 4 {
|
for n := n - 4; p <= n; p += 4 {
|
||||||
h32 += binary.LittleEndian.Uint32(buf[p:p+4]) * prime32_3
|
h32 += binary.LittleEndian.Uint32(buf[p:p+4]) * prime3
|
||||||
h32 = rol17(h32) * prime32_4
|
h32 = rol17(h32) * prime4
|
||||||
}
|
}
|
||||||
for ; p < n; p++ {
|
for ; p < n; p++ {
|
||||||
h32 += uint32(buf[p]) * prime32_5
|
h32 += uint32(buf[p]) * prime5
|
||||||
h32 = rol11(h32) * prime32_1
|
h32 = rol11(h32) * prime1
|
||||||
}
|
}
|
||||||
|
|
||||||
h32 ^= h32 >> 15
|
h32 ^= h32 >> 15
|
||||||
h32 *= prime32_2
|
h32 *= prime2
|
||||||
h32 ^= h32 >> 13
|
h32 ^= h32 >> 13
|
||||||
h32 *= prime32_3
|
h32 *= prime3
|
||||||
h32 ^= h32 >> 16
|
h32 ^= h32 >> 16
|
||||||
|
|
||||||
return h32
|
return h32
|
||||||
@ -142,19 +143,19 @@ func ChecksumZero(input []byte) uint32 {
|
|||||||
h32 := uint32(n)
|
h32 := uint32(n)
|
||||||
|
|
||||||
if n < 16 {
|
if n < 16 {
|
||||||
h32 += prime32_5
|
h32 += prime5
|
||||||
} else {
|
} else {
|
||||||
v1 := prime32_1plus2
|
v1 := prime1plus2
|
||||||
v2 := prime32_2
|
v2 := prime2
|
||||||
v3 := uint32(0)
|
v3 := uint32(0)
|
||||||
v4 := prime32_minus1
|
v4 := prime1minus
|
||||||
p := 0
|
p := 0
|
||||||
for n := n - 16; p <= n; p += 16 {
|
for n := n - 16; p <= n; p += 16 {
|
||||||
sub := input[p:][:16] //BCE hint for compiler
|
sub := input[p:][:16] //BCE hint for compiler
|
||||||
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime32_2) * prime32_1
|
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime2) * prime1
|
||||||
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime32_2) * prime32_1
|
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime2) * prime1
|
||||||
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime32_2) * prime32_1
|
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime2) * prime1
|
||||||
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime32_2) * prime32_1
|
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime2) * prime1
|
||||||
}
|
}
|
||||||
input = input[p:]
|
input = input[p:]
|
||||||
n -= p
|
n -= p
|
||||||
@ -163,19 +164,19 @@ func ChecksumZero(input []byte) uint32 {
|
|||||||
|
|
||||||
p := 0
|
p := 0
|
||||||
for n := n - 4; p <= n; p += 4 {
|
for n := n - 4; p <= n; p += 4 {
|
||||||
h32 += binary.LittleEndian.Uint32(input[p:p+4]) * prime32_3
|
h32 += binary.LittleEndian.Uint32(input[p:p+4]) * prime3
|
||||||
h32 = rol17(h32) * prime32_4
|
h32 = rol17(h32) * prime4
|
||||||
}
|
}
|
||||||
for p < n {
|
for p < n {
|
||||||
h32 += uint32(input[p]) * prime32_5
|
h32 += uint32(input[p]) * prime5
|
||||||
h32 = rol11(h32) * prime32_1
|
h32 = rol11(h32) * prime1
|
||||||
p++
|
p++
|
||||||
}
|
}
|
||||||
|
|
||||||
h32 ^= h32 >> 15
|
h32 ^= h32 >> 15
|
||||||
h32 *= prime32_2
|
h32 *= prime2
|
||||||
h32 ^= h32 >> 13
|
h32 ^= h32 >> 13
|
||||||
h32 *= prime32_3
|
h32 *= prime3
|
||||||
h32 ^= h32 >> 16
|
h32 ^= h32 >> 16
|
||||||
|
|
||||||
return h32
|
return h32
|
||||||
@ -183,12 +184,12 @@ func ChecksumZero(input []byte) uint32 {
|
|||||||
|
|
||||||
// Uint32Zero hashes x with seed 0.
|
// Uint32Zero hashes x with seed 0.
|
||||||
func Uint32Zero(x uint32) uint32 {
|
func Uint32Zero(x uint32) uint32 {
|
||||||
h := prime32_5 + 4 + x*prime32_3
|
h := prime5 + 4 + x*prime3
|
||||||
h = rol17(h) * prime32_4
|
h = rol17(h) * prime4
|
||||||
h ^= h >> 15
|
h ^= h >> 15
|
||||||
h *= prime32_2
|
h *= prime2
|
||||||
h ^= h >> 13
|
h ^= h >> 13
|
||||||
h *= prime32_3
|
h *= prime3
|
||||||
h ^= h >> 16
|
h ^= h >> 16
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
73
vendor/github.com/pierrec/lz4/lz4.go
generated
vendored
73
vendor/github.com/pierrec/lz4/lz4.go
generated
vendored
@ -10,6 +10,10 @@
|
|||||||
//
|
//
|
||||||
package lz4
|
package lz4
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Extension is the LZ4 frame file name extension
|
// Extension is the LZ4 frame file name extension
|
||||||
Extension = ".lz4"
|
Extension = ".lz4"
|
||||||
@ -30,26 +34,63 @@ const (
|
|||||||
// hashLog determines the size of the hash table used to quickly find a previous match position.
|
// hashLog determines the size of the hash table used to quickly find a previous match position.
|
||||||
// Its value influences the compression speed and memory usage, the lower the faster,
|
// Its value influences the compression speed and memory usage, the lower the faster,
|
||||||
// but at the expense of the compression ratio.
|
// but at the expense of the compression ratio.
|
||||||
// 16 seems to be the best compromise.
|
// 16 seems to be the best compromise for fast compression.
|
||||||
hashLog = 16
|
hashLog = 16
|
||||||
hashTableSize = 1 << hashLog
|
htSize = 1 << hashLog
|
||||||
hashShift = uint((minMatch * 8) - hashLog)
|
|
||||||
|
|
||||||
mfLimit = 8 + minMatch // The last match cannot start within the last 12 bytes.
|
mfLimit = 10 + minMatch // The last match cannot start within the last 14 bytes.
|
||||||
skipStrength = 6 // variable step for fast scan
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// map the block max size id with its value in bytes: 64Kb, 256Kb, 1Mb and 4Mb.
|
// map the block max size id with its value in bytes: 64Kb, 256Kb, 1Mb and 4Mb.
|
||||||
var (
|
const (
|
||||||
bsMapID = map[byte]int{4: 64 << 10, 5: 256 << 10, 6: 1 << 20, 7: 4 << 20}
|
blockSize64K = 1 << (16 + 2*iota)
|
||||||
bsMapValue = make(map[int]byte, len(bsMapID))
|
blockSize256K
|
||||||
|
blockSize1M
|
||||||
|
blockSize4M
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reversed.
|
var (
|
||||||
func init() {
|
// Keep a pool of buffers for each valid block sizes.
|
||||||
for i, v := range bsMapID {
|
bsMapValue = [...]*sync.Pool{
|
||||||
bsMapValue[v] = i
|
newBufferPool(2 * blockSize64K),
|
||||||
|
newBufferPool(2 * blockSize256K),
|
||||||
|
newBufferPool(2 * blockSize1M),
|
||||||
|
newBufferPool(2 * blockSize4M),
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// newBufferPool returns a pool for buffers of the given size.
|
||||||
|
func newBufferPool(size int) *sync.Pool {
|
||||||
|
return &sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, size)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBuffer returns a buffer to its pool.
|
||||||
|
func getBuffer(size int) []byte {
|
||||||
|
idx := blockSizeValueToIndex(size) - 4
|
||||||
|
return bsMapValue[idx].Get().([]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// putBuffer returns a buffer to its pool.
|
||||||
|
func putBuffer(size int, buf []byte) {
|
||||||
|
if cap(buf) > 0 {
|
||||||
|
idx := blockSizeValueToIndex(size) - 4
|
||||||
|
bsMapValue[idx].Put(buf[:cap(buf)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func blockSizeIndexToValue(i byte) int {
|
||||||
|
return 1 << (16 + 2*uint(i))
|
||||||
|
}
|
||||||
|
func isValidBlockSize(size int) bool {
|
||||||
|
const blockSizeMask = blockSize64K | blockSize256K | blockSize1M | blockSize4M
|
||||||
|
|
||||||
|
return size&blockSizeMask > 0 && bits.OnesCount(uint(size)) == 1
|
||||||
|
}
|
||||||
|
func blockSizeValueToIndex(size int) byte {
|
||||||
|
return 4 + byte(bits.TrailingZeros(uint(size)>>16)/2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header describes the various flags that can be set on a Writer or obtained from a Reader.
|
// Header describes the various flags that can be set on a Writer or obtained from a Reader.
|
||||||
@ -57,7 +98,7 @@ func init() {
|
|||||||
// (http://fastcompression.blogspot.com/2013/04/lz4-streaming-format-final.html).
|
// (http://fastcompression.blogspot.com/2013/04/lz4-streaming-format-final.html).
|
||||||
//
|
//
|
||||||
// NB. in a Reader, in case of concatenated frames, the Header values may change between Read() calls.
|
// NB. in a Reader, in case of concatenated frames, the Header values may change between Read() calls.
|
||||||
// It is the caller responsibility to check them if necessary.
|
// It is the caller's responsibility to check them if necessary.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
BlockChecksum bool // Compressed blocks checksum flag.
|
BlockChecksum bool // Compressed blocks checksum flag.
|
||||||
NoChecksum bool // Frame checksum flag.
|
NoChecksum bool // Frame checksum flag.
|
||||||
@ -66,3 +107,7 @@ type Header struct {
|
|||||||
CompressionLevel int // Compression level (higher is better, use 0 for fastest compression).
|
CompressionLevel int // Compression level (higher is better, use 0 for fastest compression).
|
||||||
done bool // Header processed flag (Read or Write and checked).
|
done bool // Header processed flag (Read or Write and checked).
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Header) Reset() {
|
||||||
|
h.done = false
|
||||||
|
}
|
||||||
|
52
vendor/github.com/pierrec/lz4/reader.go
generated
vendored
52
vendor/github.com/pierrec/lz4/reader.go
generated
vendored
@ -14,6 +14,9 @@ import (
|
|||||||
// The Header may change between Read() calls in case of concatenated frames.
|
// The Header may change between Read() calls in case of concatenated frames.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
Header
|
Header
|
||||||
|
// Handler called when a block has been successfully read.
|
||||||
|
// It provides the number of bytes read.
|
||||||
|
OnBlockDone func(size int)
|
||||||
|
|
||||||
buf [8]byte // Scrap buffer.
|
buf [8]byte // Scrap buffer.
|
||||||
pos int64 // Current position in src.
|
pos int64 // Current position in src.
|
||||||
@ -22,6 +25,8 @@ type Reader struct {
|
|||||||
data []byte // Uncompressed data.
|
data []byte // Uncompressed data.
|
||||||
idx int // Index of unread bytes into data.
|
idx int // Index of unread bytes into data.
|
||||||
checksum xxh32.XXHZero // Frame hash.
|
checksum xxh32.XXHZero // Frame hash.
|
||||||
|
skip int64 // Bytes to skip before next read.
|
||||||
|
dpos int64 // Position in dest
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReader returns a new LZ4 frame decoder.
|
// NewReader returns a new LZ4 frame decoder.
|
||||||
@ -76,17 +81,17 @@ func (z *Reader) readHeader(first bool) error {
|
|||||||
return fmt.Errorf("lz4: invalid version: got %d; expected %d", v, Version)
|
return fmt.Errorf("lz4: invalid version: got %d; expected %d", v, Version)
|
||||||
}
|
}
|
||||||
if b>>5&1 == 0 {
|
if b>>5&1 == 0 {
|
||||||
return fmt.Errorf("lz4: block dependency not supported")
|
return ErrBlockDependency
|
||||||
}
|
}
|
||||||
z.BlockChecksum = b>>4&1 > 0
|
z.BlockChecksum = b>>4&1 > 0
|
||||||
frameSize := b>>3&1 > 0
|
frameSize := b>>3&1 > 0
|
||||||
z.NoChecksum = b>>2&1 == 0
|
z.NoChecksum = b>>2&1 == 0
|
||||||
|
|
||||||
bmsID := buf[1] >> 4 & 0x7
|
bmsID := buf[1] >> 4 & 0x7
|
||||||
bSize, ok := bsMapID[bmsID]
|
if bmsID < 4 || bmsID > 7 {
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("lz4: invalid block max size ID: %d", bmsID)
|
return fmt.Errorf("lz4: invalid block max size ID: %d", bmsID)
|
||||||
}
|
}
|
||||||
|
bSize := blockSizeIndexToValue(bmsID - 4)
|
||||||
z.BlockMaxSize = bSize
|
z.BlockMaxSize = bSize
|
||||||
|
|
||||||
// Allocate the compressed/uncompressed buffers.
|
// Allocate the compressed/uncompressed buffers.
|
||||||
@ -101,7 +106,7 @@ func (z *Reader) readHeader(first bool) error {
|
|||||||
z.data = z.zdata[:cap(z.zdata)][bSize:]
|
z.data = z.zdata[:cap(z.zdata)][bSize:]
|
||||||
z.idx = len(z.data)
|
z.idx = len(z.data)
|
||||||
|
|
||||||
z.checksum.Write(buf[0:2])
|
_, _ = z.checksum.Write(buf[0:2])
|
||||||
|
|
||||||
if frameSize {
|
if frameSize {
|
||||||
buf := buf[:8]
|
buf := buf[:8]
|
||||||
@ -110,7 +115,7 @@ func (z *Reader) readHeader(first bool) error {
|
|||||||
}
|
}
|
||||||
z.Size = binary.LittleEndian.Uint64(buf)
|
z.Size = binary.LittleEndian.Uint64(buf)
|
||||||
z.pos += 8
|
z.pos += 8
|
||||||
z.checksum.Write(buf)
|
_, _ = z.checksum.Write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header checksum.
|
// Header checksum.
|
||||||
@ -158,6 +163,9 @@ func (z *Reader) Read(buf []byte) (int, error) {
|
|||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("reading block from writer")
|
debug("reading block from writer")
|
||||||
}
|
}
|
||||||
|
// Reset uncompressed buffer
|
||||||
|
z.data = z.zdata[:cap(z.zdata)][len(z.zdata):]
|
||||||
|
|
||||||
// Block length: 0 = end of frame, highest bit set: uncompressed.
|
// Block length: 0 = end of frame, highest bit set: uncompressed.
|
||||||
bLen, err := z.readUint32()
|
bLen, err := z.readUint32()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -208,6 +216,9 @@ func (z *Reader) Read(buf []byte) (int, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
z.pos += int64(bLen)
|
z.pos += int64(bLen)
|
||||||
|
if z.OnBlockDone != nil {
|
||||||
|
z.OnBlockDone(int(bLen))
|
||||||
|
}
|
||||||
|
|
||||||
if z.BlockChecksum {
|
if z.BlockChecksum {
|
||||||
checksum, err := z.readUint32()
|
checksum, err := z.readUint32()
|
||||||
@ -252,10 +263,13 @@ func (z *Reader) Read(buf []byte) (int, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
z.data = z.data[:n]
|
z.data = z.data[:n]
|
||||||
|
if z.OnBlockDone != nil {
|
||||||
|
z.OnBlockDone(n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !z.NoChecksum {
|
if !z.NoChecksum {
|
||||||
z.checksum.Write(z.data)
|
_, _ = z.checksum.Write(z.data)
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("current frame checksum %x", z.checksum.Sum32())
|
debug("current frame checksum %x", z.checksum.Sum32())
|
||||||
}
|
}
|
||||||
@ -263,8 +277,20 @@ func (z *Reader) Read(buf []byte) (int, error) {
|
|||||||
z.idx = 0
|
z.idx = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if z.skip > int64(len(z.data[z.idx:])) {
|
||||||
|
z.skip -= int64(len(z.data[z.idx:]))
|
||||||
|
z.dpos += int64(len(z.data[z.idx:]))
|
||||||
|
z.idx = len(z.data)
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
z.idx += int(z.skip)
|
||||||
|
z.dpos += z.skip
|
||||||
|
z.skip = 0
|
||||||
|
|
||||||
n := copy(buf, z.data[z.idx:])
|
n := copy(buf, z.data[z.idx:])
|
||||||
z.idx += n
|
z.idx += n
|
||||||
|
z.dpos += int64(n)
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("copied %d bytes to input", n)
|
debug("copied %d bytes to input", n)
|
||||||
}
|
}
|
||||||
@ -272,6 +298,20 @@ func (z *Reader) Read(buf []byte) (int, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seek implements io.Seeker, but supports seeking forward from the current
|
||||||
|
// position only. Any other seek will return an error. Allows skipping output
|
||||||
|
// bytes which aren't needed, which in some scenarios is faster than reading
|
||||||
|
// and discarding them.
|
||||||
|
// Note this may cause future calls to Read() to read 0 bytes if all of the
|
||||||
|
// data they would have returned is skipped.
|
||||||
|
func (z *Reader) Seek(offset int64, whence int) (int64, error) {
|
||||||
|
if offset < 0 || whence != io.SeekCurrent {
|
||||||
|
return z.dpos + z.skip, ErrUnsupportedSeek
|
||||||
|
}
|
||||||
|
z.skip += offset
|
||||||
|
return z.dpos + z.skip, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Reset discards the Reader's state and makes it equivalent to the
|
// Reset discards the Reader's state and makes it equivalent to the
|
||||||
// result of its original state from NewReader, but reading from r instead.
|
// result of its original state from NewReader, but reading from r instead.
|
||||||
// This permits reusing a Reader rather than allocating a new one.
|
// This permits reusing a Reader rather than allocating a new one.
|
||||||
|
231
vendor/github.com/pierrec/lz4/writer.go
generated
vendored
231
vendor/github.com/pierrec/lz4/writer.go
generated
vendored
@ -3,22 +3,35 @@ package lz4
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/pierrec/lz4/internal/xxh32"
|
"github.com/pierrec/lz4/internal/xxh32"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// zResult contains the results of compressing a block.
|
||||||
|
type zResult struct {
|
||||||
|
size uint32 // Block header
|
||||||
|
data []byte // Compressed data
|
||||||
|
checksum uint32 // Data checksum
|
||||||
|
}
|
||||||
|
|
||||||
// Writer implements the LZ4 frame encoder.
|
// Writer implements the LZ4 frame encoder.
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
Header
|
Header
|
||||||
|
// Handler called when a block has been successfully written out.
|
||||||
|
// It provides the number of bytes written.
|
||||||
|
OnBlockDone func(size int)
|
||||||
|
|
||||||
buf [19]byte // magic number(4) + header(flags(2)+[Size(8)+DictID(4)]+checksum(1)) does not exceed 19 bytes
|
buf [19]byte // magic number(4) + header(flags(2)+[Size(8)+DictID(4)]+checksum(1)) does not exceed 19 bytes
|
||||||
dst io.Writer // Destination.
|
dst io.Writer // Destination.
|
||||||
checksum xxh32.XXHZero // Frame checksum.
|
checksum xxh32.XXHZero // Frame checksum.
|
||||||
zdata []byte // Compressed data.
|
data []byte // Data to be compressed + buffer for compressed data.
|
||||||
data []byte // Data to be compressed.
|
|
||||||
idx int // Index into data.
|
idx int // Index into data.
|
||||||
hashtable [winSize]int // Hash table used in CompressBlock().
|
hashtable [winSize]int // Hash table used in CompressBlock().
|
||||||
|
|
||||||
|
// For concurrency.
|
||||||
|
c chan chan zResult // Channel for block compression goroutines and writer goroutine.
|
||||||
|
err error // Any error encountered while writing to the underlying destination.
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter returns a new LZ4 frame encoder.
|
// NewWriter returns a new LZ4 frame encoder.
|
||||||
@ -26,28 +39,92 @@ type Writer struct {
|
|||||||
// The supplied Header is checked at the first Write.
|
// The supplied Header is checked at the first Write.
|
||||||
// It is ok to change it before the first Write but then not until a Reset() is performed.
|
// It is ok to change it before the first Write but then not until a Reset() is performed.
|
||||||
func NewWriter(dst io.Writer) *Writer {
|
func NewWriter(dst io.Writer) *Writer {
|
||||||
return &Writer{dst: dst}
|
z := new(Writer)
|
||||||
|
z.Reset(dst)
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithConcurrency sets the number of concurrent go routines used for compression.
|
||||||
|
// A negative value sets the concurrency to GOMAXPROCS.
|
||||||
|
func (z *Writer) WithConcurrency(n int) *Writer {
|
||||||
|
switch {
|
||||||
|
case n == 0 || n == 1:
|
||||||
|
z.c = nil
|
||||||
|
return z
|
||||||
|
case n < 0:
|
||||||
|
n = runtime.GOMAXPROCS(0)
|
||||||
|
}
|
||||||
|
z.c = make(chan chan zResult, n)
|
||||||
|
// Writer goroutine managing concurrent block compression goroutines.
|
||||||
|
go func() {
|
||||||
|
// Process next block compression item.
|
||||||
|
for c := range z.c {
|
||||||
|
// Read the next compressed block result.
|
||||||
|
// Waiting here ensures that the blocks are output in the order they were sent.
|
||||||
|
// The incoming channel is always closed as it indicates to the caller that
|
||||||
|
// the block has been processed.
|
||||||
|
res := <-c
|
||||||
|
n := len(res.data)
|
||||||
|
if n == 0 {
|
||||||
|
// Notify the block compression routine that we are done with its result.
|
||||||
|
// This is used when a sentinel block is sent to terminate the compression.
|
||||||
|
close(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Write the block.
|
||||||
|
if err := z.writeUint32(res.size); err != nil && z.err == nil {
|
||||||
|
z.err = err
|
||||||
|
}
|
||||||
|
if _, err := z.dst.Write(res.data); err != nil && z.err == nil {
|
||||||
|
z.err = err
|
||||||
|
}
|
||||||
|
if z.BlockChecksum {
|
||||||
|
if err := z.writeUint32(res.checksum); err != nil && z.err == nil {
|
||||||
|
z.err = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isCompressed := res.size&compressedBlockFlag == 0; isCompressed {
|
||||||
|
// It is now safe to release the buffer as no longer in use by any goroutine.
|
||||||
|
putBuffer(cap(res.data), res.data)
|
||||||
|
}
|
||||||
|
if h := z.OnBlockDone; h != nil {
|
||||||
|
h(n)
|
||||||
|
}
|
||||||
|
close(c)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
|
||||||
|
// newBuffers instantiates new buffers which size matches the one in Header.
|
||||||
|
// The returned buffers are for decompression and compression respectively.
|
||||||
|
func (z *Writer) newBuffers() {
|
||||||
|
bSize := z.Header.BlockMaxSize
|
||||||
|
buf := getBuffer(bSize)
|
||||||
|
z.data = buf[:bSize] // Uncompressed buffer is the first half.
|
||||||
|
}
|
||||||
|
|
||||||
|
// freeBuffers puts the writer's buffers back to the pool.
|
||||||
|
func (z *Writer) freeBuffers() {
|
||||||
|
// Put the buffer back into the pool, if any.
|
||||||
|
putBuffer(z.Header.BlockMaxSize, z.data)
|
||||||
|
z.data = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeHeader builds and writes the header (magic+header) to the underlying io.Writer.
|
// writeHeader builds and writes the header (magic+header) to the underlying io.Writer.
|
||||||
func (z *Writer) writeHeader() error {
|
func (z *Writer) writeHeader() error {
|
||||||
// Default to 4Mb if BlockMaxSize is not set.
|
// Default to 4Mb if BlockMaxSize is not set.
|
||||||
if z.Header.BlockMaxSize == 0 {
|
if z.Header.BlockMaxSize == 0 {
|
||||||
z.Header.BlockMaxSize = bsMapID[7]
|
z.Header.BlockMaxSize = blockSize4M
|
||||||
}
|
}
|
||||||
// The only option that needs to be validated.
|
// The only option that needs to be validated.
|
||||||
bSize := z.Header.BlockMaxSize
|
bSize := z.Header.BlockMaxSize
|
||||||
bSizeID, ok := bsMapValue[bSize]
|
if !isValidBlockSize(z.Header.BlockMaxSize) {
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("lz4: invalid block max size: %d", bSize)
|
return fmt.Errorf("lz4: invalid block max size: %d", bSize)
|
||||||
}
|
}
|
||||||
// Allocate the compressed/uncompressed buffers.
|
// Allocate the compressed/uncompressed buffers.
|
||||||
// The compressed buffer cannot exceed the uncompressed one.
|
// The compressed buffer cannot exceed the uncompressed one.
|
||||||
if n := 2 * bSize; cap(z.zdata) < n {
|
z.newBuffers()
|
||||||
z.zdata = make([]byte, n, n)
|
|
||||||
}
|
|
||||||
z.zdata = z.zdata[:bSize]
|
|
||||||
z.data = z.zdata[:cap(z.zdata)][bSize:]
|
|
||||||
z.idx = 0
|
z.idx = 0
|
||||||
|
|
||||||
// Size is optional.
|
// Size is optional.
|
||||||
@ -67,7 +144,7 @@ func (z *Writer) writeHeader() error {
|
|||||||
flg |= 1 << 2
|
flg |= 1 << 2
|
||||||
}
|
}
|
||||||
buf[4] = flg
|
buf[4] = flg
|
||||||
buf[5] = bSizeID << 4
|
buf[5] = blockSizeValueToIndex(z.Header.BlockMaxSize) << 4
|
||||||
|
|
||||||
// Current buffer size: magic(4) + flags(1) + block max size (1).
|
// Current buffer size: magic(4) + flags(1) + block max size (1).
|
||||||
n := 6
|
n := 6
|
||||||
@ -147,28 +224,34 @@ func (z *Writer) Write(buf []byte) (int, error) {
|
|||||||
// compressBlock compresses a block.
|
// compressBlock compresses a block.
|
||||||
func (z *Writer) compressBlock(data []byte) error {
|
func (z *Writer) compressBlock(data []byte) error {
|
||||||
if !z.NoChecksum {
|
if !z.NoChecksum {
|
||||||
z.checksum.Write(data)
|
_, _ = z.checksum.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if z.c != nil {
|
||||||
|
c := make(chan zResult)
|
||||||
|
z.c <- c // Send now to guarantee order
|
||||||
|
go writerCompressBlock(c, z.Header, data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
zdata := z.data[z.Header.BlockMaxSize:cap(z.data)]
|
||||||
// The compressed block size cannot exceed the input's.
|
// The compressed block size cannot exceed the input's.
|
||||||
var zn int
|
var zn int
|
||||||
var err error
|
|
||||||
|
|
||||||
if level := z.Header.CompressionLevel; level != 0 {
|
if level := z.Header.CompressionLevel; level != 0 {
|
||||||
zn, err = CompressBlockHC(data, z.zdata, level)
|
zn, _ = CompressBlockHC(data, zdata, level)
|
||||||
} else {
|
} else {
|
||||||
zn, err = CompressBlock(data, z.zdata, z.hashtable[:])
|
zn, _ = CompressBlock(data, zdata, z.hashtable[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
var zdata []byte
|
|
||||||
var bLen uint32
|
var bLen uint32
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("block compression %d => %d", len(data), zn)
|
debug("block compression %d => %d", len(data), zn)
|
||||||
}
|
}
|
||||||
if err == nil && zn > 0 && zn < len(data) {
|
if zn > 0 && zn < len(data) {
|
||||||
// Compressible and compressed size smaller than uncompressed: ok!
|
// Compressible and compressed size smaller than uncompressed: ok!
|
||||||
bLen = uint32(zn)
|
bLen = uint32(zn)
|
||||||
zdata = z.zdata[:zn]
|
zdata = zdata[:zn]
|
||||||
} else {
|
} else {
|
||||||
// Uncompressed block.
|
// Uncompressed block.
|
||||||
bLen = uint32(len(data)) | compressedBlockFlag
|
bLen = uint32(len(data)) | compressedBlockFlag
|
||||||
@ -182,24 +265,26 @@ func (z *Writer) compressBlock(data []byte) error {
|
|||||||
if err := z.writeUint32(bLen); err != nil {
|
if err := z.writeUint32(bLen); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := z.dst.Write(zdata); err != nil {
|
written, err := z.dst.Write(zdata)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if h := z.OnBlockDone; h != nil {
|
||||||
|
h(written)
|
||||||
|
}
|
||||||
|
|
||||||
if z.BlockChecksum {
|
if !z.BlockChecksum {
|
||||||
checksum := xxh32.ChecksumZero(zdata)
|
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("block checksum %x", checksum)
|
debug("current frame checksum %x", z.checksum.Sum32())
|
||||||
}
|
|
||||||
if err := z.writeUint32(checksum); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
checksum := xxh32.ChecksumZero(zdata)
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("current frame checksum %x", z.checksum.Sum32())
|
debug("block checksum %x", checksum)
|
||||||
|
defer func() { debug("current frame checksum %x", z.checksum.Sum32()) }()
|
||||||
}
|
}
|
||||||
|
return z.writeUint32(checksum)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush flushes any pending compressed data to the underlying writer.
|
// Flush flushes any pending compressed data to the underlying writer.
|
||||||
@ -213,7 +298,33 @@ func (z *Writer) Flush() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return z.compressBlock(z.data[:z.idx])
|
data := z.data[:z.idx]
|
||||||
|
z.idx = 0
|
||||||
|
if z.c == nil {
|
||||||
|
return z.compressBlock(data)
|
||||||
|
}
|
||||||
|
if !z.NoChecksum {
|
||||||
|
_, _ = z.checksum.Write(data)
|
||||||
|
}
|
||||||
|
c := make(chan zResult)
|
||||||
|
z.c <- c
|
||||||
|
writerCompressBlock(c, z.Header, data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (z *Writer) close() error {
|
||||||
|
if z.c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Send a sentinel block (no data to compress) to terminate the writer main goroutine.
|
||||||
|
c := make(chan zResult)
|
||||||
|
z.c <- c
|
||||||
|
c <- zResult{}
|
||||||
|
// Wait for the main goroutine to complete.
|
||||||
|
<-c
|
||||||
|
// At this point the main goroutine has shut down or is about to return.
|
||||||
|
z.c = nil
|
||||||
|
return z.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the Writer, flushing any unwritten data to the underlying io.Writer, but does not close the underlying io.Writer.
|
// Close closes the Writer, flushing any unwritten data to the underlying io.Writer, but does not close the underlying io.Writer.
|
||||||
@ -223,10 +334,13 @@ func (z *Writer) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := z.Flush(); err != nil {
|
if err := z.Flush(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := z.close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
z.freeBuffers()
|
||||||
|
|
||||||
if debugFlag {
|
if debugFlag {
|
||||||
debug("writing last empty block")
|
debug("writing last empty block")
|
||||||
@ -234,28 +348,29 @@ func (z *Writer) Close() error {
|
|||||||
if err := z.writeUint32(0); err != nil {
|
if err := z.writeUint32(0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !z.NoChecksum {
|
if z.NoChecksum {
|
||||||
checksum := z.checksum.Sum32()
|
return nil
|
||||||
if debugFlag {
|
|
||||||
debug("stream checksum %x", checksum)
|
|
||||||
}
|
|
||||||
if err := z.writeUint32(checksum); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
checksum := z.checksum.Sum32()
|
||||||
|
if debugFlag {
|
||||||
|
debug("stream checksum %x", checksum)
|
||||||
|
}
|
||||||
|
return z.writeUint32(checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears the state of the Writer z such that it is equivalent to its
|
// Reset clears the state of the Writer z such that it is equivalent to its
|
||||||
// initial state from NewWriter, but instead writing to w.
|
// initial state from NewWriter, but instead writing to w.
|
||||||
// No access to the underlying io.Writer is performed.
|
// No access to the underlying io.Writer is performed.
|
||||||
func (z *Writer) Reset(w io.Writer) {
|
func (z *Writer) Reset(w io.Writer) {
|
||||||
z.Header = Header{}
|
n := cap(z.c)
|
||||||
|
_ = z.close()
|
||||||
|
z.freeBuffers()
|
||||||
|
z.Header.Reset()
|
||||||
z.dst = w
|
z.dst = w
|
||||||
z.checksum.Reset()
|
z.checksum.Reset()
|
||||||
z.zdata = z.zdata[:0]
|
|
||||||
z.data = z.data[:0]
|
|
||||||
z.idx = 0
|
z.idx = 0
|
||||||
|
z.err = nil
|
||||||
|
z.WithConcurrency(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeUint32 writes a uint32 to the underlying writer.
|
// writeUint32 writes a uint32 to the underlying writer.
|
||||||
@ -265,3 +380,29 @@ func (z *Writer) writeUint32(x uint32) error {
|
|||||||
_, err := z.dst.Write(buf)
|
_, err := z.dst.Write(buf)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writerCompressBlock compresses data into a pooled buffer and writes its result
|
||||||
|
// out to the input channel.
|
||||||
|
func writerCompressBlock(c chan zResult, header Header, data []byte) {
|
||||||
|
zdata := getBuffer(header.BlockMaxSize)
|
||||||
|
// The compressed block size cannot exceed the input's.
|
||||||
|
var zn int
|
||||||
|
if level := header.CompressionLevel; level != 0 {
|
||||||
|
zn, _ = CompressBlockHC(data, zdata, level)
|
||||||
|
} else {
|
||||||
|
var hashTable [winSize]int
|
||||||
|
zn, _ = CompressBlock(data, zdata, hashTable[:])
|
||||||
|
}
|
||||||
|
var res zResult
|
||||||
|
if zn > 0 && zn < len(data) {
|
||||||
|
res.size = uint32(zn)
|
||||||
|
res.data = zdata[:zn]
|
||||||
|
} else {
|
||||||
|
res.size = uint32(len(data)) | compressedBlockFlag
|
||||||
|
res.data = data
|
||||||
|
}
|
||||||
|
if header.BlockChecksum {
|
||||||
|
res.checksum = xxh32.ChecksumZero(res.data)
|
||||||
|
}
|
||||||
|
c <- res
|
||||||
|
}
|
||||||
|
12
vendor/golang.org/x/crypto/pkcs12/pkcs12.go
generated
vendored
12
vendor/golang.org/x/crypto/pkcs12/pkcs12.go
generated
vendored
@ -30,6 +30,8 @@ var (
|
|||||||
oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
|
oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
|
||||||
oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
|
oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
|
||||||
oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
|
oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
|
||||||
|
|
||||||
|
errUnknownAttributeOID = errors.New("pkcs12: unknown attribute OID")
|
||||||
)
|
)
|
||||||
|
|
||||||
type pfxPdu struct {
|
type pfxPdu struct {
|
||||||
@ -104,6 +106,11 @@ func unmarshal(in []byte, out interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToPEM converts all "safe bags" contained in pfxData to PEM blocks.
|
// ToPEM converts all "safe bags" contained in pfxData to PEM blocks.
|
||||||
|
// Unknown attributes are discarded.
|
||||||
|
//
|
||||||
|
// Note that although the returned PEM blocks for private keys have type
|
||||||
|
// "PRIVATE KEY", the bytes are not encoded according to PKCS #8, but according
|
||||||
|
// to PKCS #1 for RSA keys and SEC 1 for ECDSA keys.
|
||||||
func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
|
func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
|
||||||
encodedPassword, err := bmpString(password)
|
encodedPassword, err := bmpString(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -135,6 +142,9 @@ func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
|
|||||||
|
|
||||||
for _, attribute := range bag.Attributes {
|
for _, attribute := range bag.Attributes {
|
||||||
k, v, err := convertAttribute(&attribute)
|
k, v, err := convertAttribute(&attribute)
|
||||||
|
if err == errUnknownAttributeOID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -188,7 +198,7 @@ func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error)
|
|||||||
key = "Microsoft CSP Name"
|
key = "Microsoft CSP Name"
|
||||||
isString = true
|
isString = true
|
||||||
default:
|
default:
|
||||||
return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
|
return "", "", errUnknownAttributeOID
|
||||||
}
|
}
|
||||||
|
|
||||||
if isString {
|
if isString {
|
||||||
|
22
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
22
vendor/golang.org/x/crypto/ssh/client_auth.go
generated
vendored
@ -36,7 +36,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
|||||||
|
|
||||||
// during the authentication phase the client first attempts the "none" method
|
// during the authentication phase the client first attempts the "none" method
|
||||||
// then any untried methods suggested by the server.
|
// then any untried methods suggested by the server.
|
||||||
tried := make(map[string]bool)
|
var tried []string
|
||||||
var lastMethods []string
|
var lastMethods []string
|
||||||
|
|
||||||
sessionID := c.transport.getSessionID()
|
sessionID := c.transport.getSessionID()
|
||||||
@ -49,7 +49,9 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
|||||||
// success
|
// success
|
||||||
return nil
|
return nil
|
||||||
} else if ok == authFailure {
|
} else if ok == authFailure {
|
||||||
tried[auth.method()] = true
|
if m := auth.method(); !contains(tried, m) {
|
||||||
|
tried = append(tried, m)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if methods == nil {
|
if methods == nil {
|
||||||
methods = lastMethods
|
methods = lastMethods
|
||||||
@ -61,7 +63,7 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
|||||||
findNext:
|
findNext:
|
||||||
for _, a := range config.Auth {
|
for _, a := range config.Auth {
|
||||||
candidateMethod := a.method()
|
candidateMethod := a.method()
|
||||||
if tried[candidateMethod] {
|
if contains(tried, candidateMethod) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, meth := range methods {
|
for _, meth := range methods {
|
||||||
@ -72,16 +74,16 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried))
|
return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", tried)
|
||||||
}
|
}
|
||||||
|
|
||||||
func keys(m map[string]bool) []string {
|
func contains(list []string, e string) bool {
|
||||||
s := make([]string, 0, len(m))
|
for _, s := range list {
|
||||||
|
if s == e {
|
||||||
for key := range m {
|
return true
|
||||||
s = append(s, key)
|
}
|
||||||
}
|
}
|
||||||
return s
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// An AuthMethod represents an instance of an RFC 4252 authentication method.
|
// An AuthMethod represents an instance of an RFC 4252 authentication method.
|
||||||
|
8
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
8
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
@ -107,6 +107,7 @@ func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMis
|
|||||||
|
|
||||||
// dialCall is an in-flight Transport dial call to a host.
|
// dialCall is an in-flight Transport dial call to a host.
|
||||||
type dialCall struct {
|
type dialCall struct {
|
||||||
|
_ incomparable
|
||||||
p *clientConnPool
|
p *clientConnPool
|
||||||
done chan struct{} // closed when done
|
done chan struct{} // closed when done
|
||||||
res *ClientConn // valid after done is closed
|
res *ClientConn // valid after done is closed
|
||||||
@ -180,6 +181,7 @@ func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c *tls.Conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
type addConnCall struct {
|
type addConnCall struct {
|
||||||
|
_ incomparable
|
||||||
p *clientConnPool
|
p *clientConnPool
|
||||||
done chan struct{} // closed when done
|
done chan struct{} // closed when done
|
||||||
err error
|
err error
|
||||||
@ -200,12 +202,6 @@ func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) {
|
|||||||
close(c.done)
|
close(c.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *clientConnPool) addConn(key string, cc *ClientConn) {
|
|
||||||
p.mu.Lock()
|
|
||||||
p.addConnLocked(key, cc)
|
|
||||||
p.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// p.mu must be held
|
// p.mu must be held
|
||||||
func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
|
func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
|
||||||
for _, v := range p.conns[key] {
|
for _, v := range p.conns[key] {
|
||||||
|
2
vendor/golang.org/x/net/http2/flow.go
generated
vendored
2
vendor/golang.org/x/net/http2/flow.go
generated
vendored
@ -8,6 +8,8 @@ package http2
|
|||||||
|
|
||||||
// flow is the flow control window's size.
|
// flow is the flow control window's size.
|
||||||
type flow struct {
|
type flow struct {
|
||||||
|
_ incomparable
|
||||||
|
|
||||||
// n is the number of DATA bytes we're allowed to send.
|
// n is the number of DATA bytes we're allowed to send.
|
||||||
// A flow is kept both on a conn and a per-stream.
|
// A flow is kept both on a conn and a per-stream.
|
||||||
n int32
|
n int32
|
||||||
|
7
vendor/golang.org/x/net/http2/hpack/huffman.go
generated
vendored
7
vendor/golang.org/x/net/http2/hpack/huffman.go
generated
vendored
@ -105,7 +105,14 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// incomparable is a zero-width, non-comparable type. Adding it to a struct
|
||||||
|
// makes that struct also non-comparable, and generally doesn't add
|
||||||
|
// any size (as long as it's first).
|
||||||
|
type incomparable [0]func()
|
||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
|
_ incomparable
|
||||||
|
|
||||||
// children is non-nil for internal nodes
|
// children is non-nil for internal nodes
|
||||||
children *[256]*node
|
children *[256]*node
|
||||||
|
|
||||||
|
7
vendor/golang.org/x/net/http2/http2.go
generated
vendored
7
vendor/golang.org/x/net/http2/http2.go
generated
vendored
@ -241,6 +241,7 @@ func (cw closeWaiter) Wait() {
|
|||||||
// Its buffered writer is lazily allocated as needed, to minimize
|
// Its buffered writer is lazily allocated as needed, to minimize
|
||||||
// idle memory usage with many connections.
|
// idle memory usage with many connections.
|
||||||
type bufferedWriter struct {
|
type bufferedWriter struct {
|
||||||
|
_ incomparable
|
||||||
w io.Writer // immutable
|
w io.Writer // immutable
|
||||||
bw *bufio.Writer // non-nil when data is buffered
|
bw *bufio.Writer // non-nil when data is buffered
|
||||||
}
|
}
|
||||||
@ -313,6 +314,7 @@ func bodyAllowedForStatus(status int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type httpError struct {
|
type httpError struct {
|
||||||
|
_ incomparable
|
||||||
msg string
|
msg string
|
||||||
timeout bool
|
timeout bool
|
||||||
}
|
}
|
||||||
@ -376,3 +378,8 @@ func (s *sorter) SortStrings(ss []string) {
|
|||||||
func validPseudoPath(v string) bool {
|
func validPseudoPath(v string) bool {
|
||||||
return (len(v) > 0 && v[0] == '/') || v == "*"
|
return (len(v) > 0 && v[0] == '/') || v == "*"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// incomparable is a zero-width, non-comparable type. Adding it to a struct
|
||||||
|
// makes that struct also non-comparable, and generally doesn't add
|
||||||
|
// any size (as long as it's first).
|
||||||
|
type incomparable [0]func()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user