diff --git a/go.mod b/go.mod index 06c6f8555..7dba40002 100644 --- a/go.mod +++ b/go.mod @@ -55,8 +55,8 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.9.0 // indirect github.com/hashicorp/consul v1.7.1-0.20200213195527-b137060630b4 github.com/hashicorp/consul-template v0.24.1 - github.com/hashicorp/consul/api v1.4.0 - github.com/hashicorp/consul/sdk v0.4.0 + github.com/hashicorp/consul/api v1.4.1-0.20200730220852-12f574c9de39 + github.com/hashicorp/consul/sdk v0.5.0 github.com/hashicorp/cronexpr v1.1.0 github.com/hashicorp/go-checkpoint v0.0.0-20171009173528-1545e56e46de github.com/hashicorp/go-cleanhttp v0.5.1 @@ -68,7 +68,7 @@ require ( github.com/hashicorp/go-immutable-radix v1.2.0 github.com/hashicorp/go-memdb v1.2.1 github.com/hashicorp/go-msgpack v1.1.5 - github.com/hashicorp/go-multierror v1.0.1-0.20191120192120-72917a1559e1 + github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-plugin v1.0.2-0.20191004171845-809113480b55 github.com/hashicorp/go-sockaddr v1.0.2 github.com/hashicorp/go-syslog v1.0.0 @@ -78,12 +78,12 @@ require ( github.com/hashicorp/hcl v1.0.1-0.20191016231534-914dc3f8dd7c github.com/hashicorp/hcl/v2 v2.5.1 github.com/hashicorp/logutils v1.0.0 - github.com/hashicorp/memberlist v0.1.6 + github.com/hashicorp/memberlist v0.2.2 github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 github.com/hashicorp/nomad/api v0.0.0-20200529203653-c4416b26d3eb github.com/hashicorp/raft v1.1.3-0.20200211192230-365023de17e6 github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea - github.com/hashicorp/serf v0.8.5 + github.com/hashicorp/serf v0.9.3 github.com/hashicorp/vault/api v1.0.5-0.20190730042357-746c0b111519 github.com/hashicorp/vault/sdk v0.1.14-0.20190730042320-0dc007d98cc8 github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d @@ -94,7 +94,7 @@ require ( github.com/kr/pty v1.1.5 github.com/kr/text v0.2.0 github.com/mattn/go-colorable v0.1.6 - github.com/mitchellh/cli v1.0.0 + github.com/mitchellh/cli v1.1.0 github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 github.com/mitchellh/copystructure v1.0.0 github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b @@ -110,7 +110,7 @@ require ( github.com/opencontainers/runtime-spec v1.0.2-0.20200307132014-f49fed0d6290 // indirect github.com/opencontainers/selinux v1.4.1-0.20200311111634-a2f0d9c2aafc // indirect github.com/pkg/errors v0.9.1 - github.com/posener/complete v1.2.1 + github.com/posener/complete v1.2.3 github.com/prometheus/client_golang v1.4.0 github.com/prometheus/common v0.9.1 github.com/rs/cors v0.0.0-20170801073201-eabcc6af4bbe diff --git a/go.sum b/go.sum index 36d9fcde1..e5027198b 100644 --- a/go.sum +++ b/go.sum @@ -318,9 +318,13 @@ github.com/hashicorp/consul-template v0.24.1/go.mod h1:KcTEopo2kCp7kww0d4oG7d3oX github.com/hashicorp/consul/api v1.2.0/go.mod h1:1SIkFYi2ZTXUE5Kgt179+4hH33djo11+0Eo2XgTAtkw= github.com/hashicorp/consul/api v1.4.0 h1:jfESivXnO5uLdH650JU/6AnjRoHrLhULq0FnC3Kp9EY= github.com/hashicorp/consul/api v1.4.0/go.mod h1:xc8u05kyMa3Wjr9eEAsIAo3dg8+LywT5E/Cl7cNS5nU= +github.com/hashicorp/consul/api v1.4.1-0.20200730220852-12f574c9de39 h1:i0o6cy+ul/lNGjX8ob+P4Ge1GH2gf1ywUE1ILtpfvFo= +github.com/hashicorp/consul/api v1.4.1-0.20200730220852-12f574c9de39/go.mod h1:GWV+sV6Rzk24M6MclFl41QeMut5J+nzoGp+6zfICuOk= github.com/hashicorp/consul/sdk v0.2.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30= github.com/hashicorp/consul/sdk v0.4.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= +github.com/hashicorp/consul/sdk v0.5.0 h1:WC4594Wp/LkEeML/OdQKEC1yqBmEYkRp6i7X5u0zDAs= +github.com/hashicorp/consul/sdk v0.5.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/cronexpr v1.1.0 h1:dnNsWtH0V2ReN7JccYe8m//Bj14+PjJDntR1dz0Cixk= github.com/hashicorp/cronexpr v1.1.0/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -361,8 +365,8 @@ github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6 github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.0.1-0.20191120192120-72917a1559e1 h1:GykKxF7ikF21GDbvpNQDQ3unj6Vf7qBeBjVQJx6s38U= -github.com/hashicorp/go-multierror v1.0.1-0.20191120192120-72917a1559e1/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-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-plugin v1.0.2-0.20191004171845-809113480b55 h1:XzRWU4VSJBqGVxl6tWD+6ITHftMhvRDKKyp1WVSXAhY= github.com/hashicorp/go-plugin v1.0.2-0.20191004171845-809113480b55/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= @@ -410,6 +414,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.6 h1:ouPxvwKYaNZe+eTcHxYP0EblPduVLvIPycul+vv8his= github.com/hashicorp/memberlist v0.1.6/go.mod h1:5VDNHjqFMgEcclnwmkCnC99IPwxBmIsxwY8qn+Nl0H4= +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/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 h1:lc3c72qGlIMDqQpQH82Y4vaglRMMFdJbziYWriR4UcE= github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69/go.mod h1:/z+jUGRBlwVpUZfjute9jWaF6/HuhjuFQuL1YXzVD1Q= github.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8= @@ -422,6 +428,8 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= github.com/hashicorp/serf v0.8.5 h1:ZynDUIQiA8usmRgPdGPHFdPnb1wgGI9tK3mO9hcAJjc= github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k= +github.com/hashicorp/serf v0.9.3 h1:AVF6JDQQens6nMHT9OGERBvK0f8rPrAGILnsKLr6lzM= +github.com/hashicorp/serf v0.9.3/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= github.com/hashicorp/vault/api v1.0.5-0.20190730042357-746c0b111519 h1:2qdbEUXjHohC+OYHtVU5lujvPAHPKYR4IMs9rsiUTk8= github.com/hashicorp/vault/api v1.0.5-0.20190730042357-746c0b111519/go.mod h1:i9PKqwFko/s/aihU1uuHGh/FaQS+Xcgvd9dvnfAvQb0= @@ -510,6 +518,8 @@ 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.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 h1:KHyL+3mQOF9sPfs26lsefckcFNDcIZtiACQiECzIUkw= github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= @@ -608,8 +618,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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.1 h1:LrvDIY//XNo65Lq84G/akBuMGlawHvGBABv8f/ZN6DI= -github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= diff --git a/vendor/github.com/hashicorp/consul/api/acl.go b/vendor/github.com/hashicorp/consul/api/acl.go index 4057344d8..7453feb8a 100644 --- a/vendor/github.com/hashicorp/consul/api/acl.go +++ b/vendor/github.com/hashicorp/consul/api/acl.go @@ -1,6 +1,7 @@ package api import ( + "encoding/json" "fmt" "io" "io/ioutil" @@ -36,7 +37,9 @@ type ACLToken struct { Policies []*ACLTokenPolicyLink `json:",omitempty"` Roles []*ACLTokenRoleLink `json:",omitempty"` ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` + NodeIdentities []*ACLNodeIdentity `json:",omitempty"` Local bool + AuthMethod string `json:",omitempty"` ExpirationTTL time.Duration `json:",omitempty"` ExpirationTime *time.Time `json:",omitempty"` CreateTime time.Time `json:",omitempty"` @@ -47,7 +50,7 @@ type ACLToken struct { Rules string `json:",omitempty"` // Namespace is the namespace the ACLToken is associated with. - // Namespaces is a Consul Enterprise feature. + // Namespaces are a Consul Enterprise feature. Namespace string `json:",omitempty"` } @@ -59,7 +62,9 @@ type ACLTokenListEntry struct { Policies []*ACLTokenPolicyLink `json:",omitempty"` Roles []*ACLTokenRoleLink `json:",omitempty"` ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` + NodeIdentities []*ACLNodeIdentity `json:",omitempty"` Local bool + AuthMethod string `json:",omitempty"` ExpirationTime *time.Time `json:",omitempty"` CreateTime time.Time Hash []byte @@ -102,6 +107,13 @@ type ACLServiceIdentity struct { Datacenters []string `json:",omitempty"` } +// ACLNodeIdentity represents a high-level grant of all necessary privileges +// to assume the identity of the named Node in the Catalog and within Connect. +type ACLNodeIdentity struct { + NodeName string + Datacenter string +} + // ACLPolicy represents an ACL Policy. type ACLPolicy struct { ID string @@ -141,6 +153,7 @@ type ACLRole struct { Description string Policies []*ACLRolePolicyLink `json:",omitempty"` ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` + NodeIdentities []*ACLNodeIdentity `json:",omitempty"` Hash []byte CreateIndex uint64 ModifyIndex uint64 @@ -180,7 +193,13 @@ type ACLBindingRule struct { type ACLAuthMethod struct { Name string Type string - Description string + DisplayName string `json:",omitempty"` + Description string `json:",omitempty"` + MaxTokenTTL time.Duration `json:",omitempty"` + + // TokenLocality defines the kind of token that this auth method produces. + // This can be either 'local' or 'global'. If empty 'local' is assumed. + TokenLocality string `json:",omitempty"` // Configuration is arbitrary configuration for the auth method. This // should only contain primitive values and containers (such as lists and @@ -190,15 +209,69 @@ type ACLAuthMethod struct { CreateIndex uint64 ModifyIndex uint64 + // NamespaceRules apply only on auth methods defined in the default namespace. + // Namespacing is a Consul Enterprise feature. + NamespaceRules []*ACLAuthMethodNamespaceRule `json:",omitempty"` + // Namespace is the namespace the ACLAuthMethod is associated with. // Namespacing is a Consul Enterprise feature. Namespace string `json:",omitempty"` } +func (m *ACLAuthMethod) MarshalJSON() ([]byte, error) { + type Alias ACLAuthMethod + exported := &struct { + MaxTokenTTL string `json:",omitempty"` + *Alias + }{ + MaxTokenTTL: m.MaxTokenTTL.String(), + Alias: (*Alias)(m), + } + if m.MaxTokenTTL == 0 { + exported.MaxTokenTTL = "" + } + + return json.Marshal(exported) +} + +func (m *ACLAuthMethod) UnmarshalJSON(data []byte) error { + type Alias ACLAuthMethod + aux := &struct { + MaxTokenTTL string + *Alias + }{ + Alias: (*Alias)(m), + } + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + var err error + if aux.MaxTokenTTL != "" { + if m.MaxTokenTTL, err = time.ParseDuration(aux.MaxTokenTTL); err != nil { + return err + } + } + + return nil +} + +type ACLAuthMethodNamespaceRule struct { + // Selector is an expression that matches against verified identity + // attributes returned from the auth method during login. + Selector string `json:",omitempty"` + + // BindNamespace is the target namespace of the binding. Can be lightly + // templated using HIL ${foo} syntax from available field names. + // + // If empty it's created in the same namespace as the auth method. + BindNamespace string `json:",omitempty"` +} + type ACLAuthMethodListEntry struct { Name string Type string - Description string + DisplayName string `json:",omitempty"` + Description string `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 @@ -246,12 +319,73 @@ func (c *KubernetesAuthMethodConfig) RenderToConfig() map[string]interface{} { } } +// OIDCAuthMethodConfig is the config for the built-in Consul auth method for +// OIDC and JWT. +type OIDCAuthMethodConfig struct { + // common for type=oidc and type=jwt + JWTSupportedAlgs []string `json:",omitempty"` + BoundAudiences []string `json:",omitempty"` + ClaimMappings map[string]string `json:",omitempty"` + ListClaimMappings map[string]string `json:",omitempty"` + OIDCDiscoveryURL string `json:",omitempty"` + OIDCDiscoveryCACert string `json:",omitempty"` + // just for type=oidc + OIDCClientID string `json:",omitempty"` + OIDCClientSecret string `json:",omitempty"` + OIDCScopes []string `json:",omitempty"` + AllowedRedirectURIs []string `json:",omitempty"` + VerboseOIDCLogging bool `json:",omitempty"` + // just for type=jwt + JWKSURL string `json:",omitempty"` + JWKSCACert string `json:",omitempty"` + JWTValidationPubKeys []string `json:",omitempty"` + BoundIssuer string `json:",omitempty"` + ExpirationLeeway time.Duration `json:",omitempty"` + NotBeforeLeeway time.Duration `json:",omitempty"` + ClockSkewLeeway time.Duration `json:",omitempty"` +} + +// RenderToConfig converts this into a map[string]interface{} suitable for use +// in the ACLAuthMethod.Config field. +func (c *OIDCAuthMethodConfig) RenderToConfig() map[string]interface{} { + return map[string]interface{}{ + // common for type=oidc and type=jwt + "JWTSupportedAlgs": c.JWTSupportedAlgs, + "BoundAudiences": c.BoundAudiences, + "ClaimMappings": c.ClaimMappings, + "ListClaimMappings": c.ListClaimMappings, + "OIDCDiscoveryURL": c.OIDCDiscoveryURL, + "OIDCDiscoveryCACert": c.OIDCDiscoveryCACert, + // just for type=oidc + "OIDCClientID": c.OIDCClientID, + "OIDCClientSecret": c.OIDCClientSecret, + "OIDCScopes": c.OIDCScopes, + "AllowedRedirectURIs": c.AllowedRedirectURIs, + "VerboseOIDCLogging": c.VerboseOIDCLogging, + // just for type=jwt + "JWKSURL": c.JWKSURL, + "JWKSCACert": c.JWKSCACert, + "JWTValidationPubKeys": c.JWTValidationPubKeys, + "BoundIssuer": c.BoundIssuer, + "ExpirationLeeway": c.ExpirationLeeway, + "NotBeforeLeeway": c.NotBeforeLeeway, + "ClockSkewLeeway": c.ClockSkewLeeway, + } +} + type ACLLoginParams struct { AuthMethod string BearerToken string Meta map[string]string `json:",omitempty"` } +type ACLOIDCAuthURLParams struct { + AuthMethod string + RedirectURI string + ClientNonce string + Meta map[string]string `json:",omitempty"` +} + // ACL can be used to query the ACL endpoints type ACL struct { c *Client @@ -666,6 +800,32 @@ func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMe return &out, qm, nil } +// PolicyReadByName retrieves the policy details including the rule set with name. +func (a *ACL) PolicyReadByName(policyName string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) { + r := a.c.newRequest("GET", "/v1/acl/policy/name/"+url.QueryEscape(policyName)) + r.setQueryOptions(q) + found, rtt, resp, err := requireNotFoundOrOK(a.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 + } + + var out ACLPolicy + if err := decodeBody(resp, &out); err != nil { + return nil, nil, err + } + + return &out, qm, nil +} + // PolicyList retrieves a listing of all policies. The listing does not include the // rules for any policy as those should be retrieved by subsequent calls to PolicyRead. func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) { @@ -1142,3 +1302,62 @@ func (a *ACL) Logout(q *WriteOptions) (*WriteMeta, error) { wm := &WriteMeta{RequestTime: rtt} return wm, nil } + +// OIDCAuthURL requests an authorization URL to start an OIDC login flow. +func (a *ACL) OIDCAuthURL(auth *ACLOIDCAuthURLParams, q *WriteOptions) (string, *WriteMeta, error) { + if auth.AuthMethod == "" { + return "", nil, fmt.Errorf("Must specify an auth method name") + } + + r := a.c.newRequest("POST", "/v1/acl/oidc/auth-url") + r.setWriteOptions(q) + r.obj = auth + + rtt, resp, err := requireOK(a.c.doRequest(r)) + if err != nil { + return "", nil, err + } + defer resp.Body.Close() + + wm := &WriteMeta{RequestTime: rtt} + var out aclOIDCAuthURLResponse + if err := decodeBody(resp, &out); err != nil { + return "", nil, err + } + return out.AuthURL, wm, nil +} + +type aclOIDCAuthURLResponse struct { + AuthURL string +} + +type ACLOIDCCallbackParams struct { + AuthMethod string + State string + Code string + ClientNonce string +} + +// OIDCCallback is the callback endpoint to complete an OIDC login. +func (a *ACL) OIDCCallback(auth *ACLOIDCCallbackParams, q *WriteOptions) (*ACLToken, *WriteMeta, error) { + if auth.AuthMethod == "" { + return nil, nil, fmt.Errorf("Must specify an auth method name") + } + + r := a.c.newRequest("POST", "/v1/acl/oidc/callback") + r.setWriteOptions(q) + r.obj = auth + + rtt, resp, err := requireOK(a.c.doRequest(r)) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + + wm := &WriteMeta{RequestTime: rtt} + var out ACLToken + if err := decodeBody(resp, &out); err != nil { + return nil, nil, err + } + return &out, wm, nil +} diff --git a/vendor/github.com/hashicorp/consul/api/agent.go b/vendor/github.com/hashicorp/consul/api/agent.go index 929d3ccd3..1baa5f0b0 100644 --- a/vendor/github.com/hashicorp/consul/api/agent.go +++ b/vendor/github.com/hashicorp/consul/api/agent.go @@ -28,6 +28,15 @@ const ( // service will proxy connections based off the SNI header set by other // connect proxies ServiceKindMeshGateway ServiceKind = "mesh-gateway" + + // ServiceKindTerminatingGateway is a Terminating Gateway for the Connect + // feature. This service will proxy connections to services outside the mesh. + ServiceKindTerminatingGateway ServiceKind = "terminating-gateway" + + // ServiceKindIngressGateway is an Ingress Gateway for the Connect feature. + // This service will ingress connections based of configuration defined in + // the ingress-gateway config entry. + ServiceKindIngressGateway ServiceKind = "ingress-gateway" ) // UpstreamDestType is the type of upstream discovery mechanism. @@ -179,26 +188,28 @@ type AgentCheckRegistration struct { // AgentServiceCheck is used to define a node or service level check type AgentServiceCheck struct { - CheckID string `json:",omitempty"` - Name string `json:",omitempty"` - Args []string `json:"ScriptArgs,omitempty"` - DockerContainerID string `json:",omitempty"` - Shell string `json:",omitempty"` // Only supported for Docker. - Interval string `json:",omitempty"` - Timeout string `json:",omitempty"` - TTL string `json:",omitempty"` - HTTP string `json:",omitempty"` - Header map[string][]string `json:",omitempty"` - Method string `json:",omitempty"` - Body string `json:",omitempty"` - TCP string `json:",omitempty"` - Status string `json:",omitempty"` - Notes string `json:",omitempty"` - TLSSkipVerify bool `json:",omitempty"` - GRPC string `json:",omitempty"` - GRPCUseTLS bool `json:",omitempty"` - AliasNode string `json:",omitempty"` - AliasService string `json:",omitempty"` + CheckID string `json:",omitempty"` + Name string `json:",omitempty"` + Args []string `json:"ScriptArgs,omitempty"` + DockerContainerID string `json:",omitempty"` + Shell string `json:",omitempty"` // Only supported for Docker. + Interval string `json:",omitempty"` + Timeout string `json:",omitempty"` + TTL string `json:",omitempty"` + HTTP string `json:",omitempty"` + Header map[string][]string `json:",omitempty"` + Method string `json:",omitempty"` + Body string `json:",omitempty"` + TCP string `json:",omitempty"` + Status string `json:",omitempty"` + Notes string `json:",omitempty"` + TLSSkipVerify bool `json:",omitempty"` + GRPC string `json:",omitempty"` + GRPCUseTLS bool `json:",omitempty"` + AliasNode string `json:",omitempty"` + AliasService string `json:",omitempty"` + SuccessBeforePassing int `json:",omitempty"` + FailuresBeforeCritical int `json:",omitempty"` // In Consul 0.7 and later, checks that are associated with a service // may also contain this optional DeregisterCriticalServiceAfter field, diff --git a/vendor/github.com/hashicorp/consul/api/api.go b/vendor/github.com/hashicorp/consul/api/api.go index a42a110bc..7b00be967 100644 --- a/vendor/github.com/hashicorp/consul/api/api.go +++ b/vendor/github.com/hashicorp/consul/api/api.go @@ -551,11 +551,11 @@ func NewClient(config *Config) (*Client, error) { // bootstrap the config defConfig := DefaultConfig() - if len(config.Address) == 0 { + if config.Address == "" { config.Address = defConfig.Address } - if len(config.Scheme) == 0 { + if config.Scheme == "" { config.Scheme = defConfig.Scheme } @@ -599,7 +599,7 @@ func NewClient(config *Config) (*Client, error) { if len(parts) == 2 { switch parts[0] { case "http": - config.Scheme = "http" + // Never revert to http if TLS was explicitly requested. case "https": config.Scheme = "https" case "unix": diff --git a/vendor/github.com/hashicorp/consul/api/catalog.go b/vendor/github.com/hashicorp/consul/api/catalog.go index dd34c17db..607d5d065 100644 --- a/vendor/github.com/hashicorp/consul/api/catalog.go +++ b/vendor/github.com/hashicorp/consul/api/catalog.go @@ -81,6 +81,29 @@ type CatalogDeregistration struct { 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 @@ -283,6 +306,27 @@ func (c *Catalog) NodeServiceList(node string, q *QueryOptions) (*CatalogNodeSer 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) diff --git a/vendor/github.com/hashicorp/consul/api/config_entry.go b/vendor/github.com/hashicorp/consul/api/config_entry.go index ae0d42797..dc31d6110 100644 --- a/vendor/github.com/hashicorp/consul/api/config_entry.go +++ b/vendor/github.com/hashicorp/consul/api/config_entry.go @@ -12,11 +12,13 @@ import ( ) const ( - ServiceDefaults string = "service-defaults" - ProxyDefaults string = "proxy-defaults" - ServiceRouter string = "service-router" - ServiceSplitter string = "service-splitter" - ServiceResolver string = "service-resolver" + 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" ) @@ -69,13 +71,13 @@ type ExposeConfig struct { type ExposePath struct { // ListenerPort defines the port of the proxy's listener for exposed paths. - ListenerPort int `json:",omitempty"` + 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"` + LocalPathPort int `json:",omitempty" alias:"local_path_port"` // Protocol describes the upstream's service protocol. // Valid values are "http" and "http2", defaults to "http" @@ -90,9 +92,9 @@ type ServiceConfigEntry struct { Name string Namespace string `json:",omitempty"` Protocol string `json:",omitempty"` - MeshGateway MeshGatewayConfig `json:",omitempty"` + MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` Expose ExposeConfig `json:",omitempty"` - ExternalSNI string `json:",omitempty"` + ExternalSNI string `json:",omitempty" alias:"external_sni"` CreateIndex uint64 ModifyIndex uint64 } @@ -118,7 +120,7 @@ type ProxyConfigEntry struct { Name string Namespace string `json:",omitempty"` Config map[string]interface{} `json:",omitempty"` - MeshGateway MeshGatewayConfig `json:",omitempty"` + MeshGateway MeshGatewayConfig `json:",omitempty" alias:"mesh_gateway"` Expose ExposeConfig `json:",omitempty"` CreateIndex uint64 ModifyIndex uint64 @@ -140,11 +142,6 @@ func (p *ProxyConfigEntry) GetModifyIndex() uint64 { return p.ModifyIndex } -type rawEntryListResponse struct { - kind string - Entries []map[string]interface{} -} - func makeConfigEntry(kind, name string) (ConfigEntry, error) { switch kind { case ServiceDefaults: @@ -157,6 +154,10 @@ func makeConfigEntry(kind, name string) (ConfigEntry, error) { 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) } diff --git a/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go b/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go index 885b78dc9..f3994f0dd 100644 --- a/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go +++ b/vendor/github.com/hashicorp/consul/api/config_entry_discoverychain.go @@ -31,12 +31,12 @@ type ServiceRouteMatch struct { } type ServiceRouteHTTPMatch struct { - PathExact string `json:",omitempty"` - PathPrefix string `json:",omitempty"` - PathRegex string `json:",omitempty"` + 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"` + QueryParam []ServiceRouteHTTPMatchQueryParam `json:",omitempty" alias:"query_param"` Methods []string `json:",omitempty"` } @@ -59,13 +59,13 @@ type ServiceRouteHTTPMatchQueryParam struct { type ServiceRouteDestination struct { Service string `json:",omitempty"` - ServiceSubset string `json:",omitempty"` + ServiceSubset string `json:",omitempty" alias:"service_subset"` Namespace string `json:",omitempty"` - PrefixRewrite string `json:",omitempty"` - RequestTimeout time.Duration `json:",omitempty"` - NumRetries uint32 `json:",omitempty"` - RetryOnConnectFailure bool `json:",omitempty"` - RetryOnStatusCodes []uint32 `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) { @@ -123,7 +123,7 @@ func (e *ServiceSplitterConfigEntry) GetModifyIndex() uint64 { return e.ModifyIn type ServiceSplit struct { Weight float32 Service string `json:",omitempty"` - ServiceSubset string `json:",omitempty"` + ServiceSubset string `json:",omitempty" alias:"service_subset"` Namespace string `json:",omitempty"` } @@ -132,11 +132,11 @@ type ServiceResolverConfigEntry struct { Name string Namespace string `json:",omitempty"` - DefaultSubset 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"` + ConnectTimeout time.Duration `json:",omitempty" alias:"connect_timeout"` CreateIndex uint64 ModifyIndex uint64 @@ -185,19 +185,19 @@ func (e *ServiceResolverConfigEntry) GetModifyIndex() uint64 { return e.ModifyIn type ServiceResolverSubset struct { Filter string `json:",omitempty"` - OnlyPassing bool `json:",omitempty"` + OnlyPassing bool `json:",omitempty" alias:"only_passing"` } type ServiceResolverRedirect struct { Service string `json:",omitempty"` - ServiceSubset 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"` + ServiceSubset string `json:",omitempty" alias:"service_subset"` Namespace string `json:",omitempty"` Datacenters []string `json:",omitempty"` } diff --git a/vendor/github.com/hashicorp/consul/api/config_entry_gateways.go b/vendor/github.com/hashicorp/consul/api/config_entry_gateways.go new file mode 100644 index 000000000..13a5ec707 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/api/config_entry_gateways.go @@ -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 + // ".*" 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 +} diff --git a/vendor/github.com/hashicorp/consul/api/connect_intention.go b/vendor/github.com/hashicorp/consul/api/connect_intention.go index d25cb844f..3db177c7b 100644 --- a/vendor/github.com/hashicorp/consul/api/connect_intention.go +++ b/vendor/github.com/hashicorp/consul/api/connect_intention.go @@ -33,7 +33,7 @@ type Intention struct { // SourceType is the type of the value for the source. SourceType IntentionSourceType - // Action is whether this is a whitelist or blacklist intention. + // Action is whether this is an allowlist or denylist intention. Action IntentionAction // DefaultAddr, DefaultPort of the local listening proxy (if any) to @@ -99,7 +99,7 @@ func (i *Intention) partString(ns, n string) string { const IntentionDefaultNamespace = "default" // IntentionAction is the action that the intention represents. This -// can be "allow" or "deny" to whitelist or blacklist intentions. +// can be "allow" or "deny" to allowlist or denylist intentions. type IntentionAction string const ( diff --git a/vendor/github.com/hashicorp/consul/api/go.mod b/vendor/github.com/hashicorp/consul/api/go.mod index 7770aae90..ab62e8e9f 100644 --- a/vendor/github.com/hashicorp/consul/api/go.mod +++ b/vendor/github.com/hashicorp/consul/api/go.mod @@ -10,7 +10,7 @@ require ( 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.8.2 + github.com/hashicorp/serf v0.9.3 github.com/mitchellh/mapstructure v1.1.2 github.com/stretchr/testify v1.4.0 ) diff --git a/vendor/github.com/hashicorp/consul/api/go.sum b/vendor/github.com/hashicorp/consul/api/go.sum index 40f6fdc74..3c26420cd 100644 --- a/vendor/github.com/hashicorp/consul/api/go.sum +++ b/vendor/github.com/hashicorp/consul/api/go.sum @@ -2,6 +2,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC 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= @@ -12,8 +13,6 @@ 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/consul/sdk v0.4.0 h1:zBtCfKJZcJDBvSCkQJch4ulp59m1rATFLKwNo/LYY30= -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/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= @@ -26,6 +25,8 @@ github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqk 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= @@ -34,15 +35,14 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv 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/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= 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.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +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= @@ -51,6 +51,8 @@ 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= @@ -60,13 +62,13 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX 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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +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/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -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 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -77,32 +79,48 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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= diff --git a/vendor/github.com/hashicorp/consul/api/health.go b/vendor/github.com/hashicorp/consul/api/health.go index 2f4894ae6..99b9ac257 100644 --- a/vendor/github.com/hashicorp/consul/api/health.go +++ b/vendor/github.com/hashicorp/consul/api/health.go @@ -17,6 +17,12 @@ const ( 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" @@ -170,7 +176,7 @@ type HealthChecks []*HealthCheck func (c HealthChecks) AggregatedStatus() string { var passing, warning, critical, maintenance bool for _, check := range c { - id := string(check.CheckID) + id := check.CheckID if id == NodeMaint || strings.HasPrefix(id, ServiceMaintPrefix) { maintenance = true continue @@ -269,11 +275,11 @@ func (h *Health) Service(service, tag string, passingOnly bool, q *QueryOptions) if tag != "" { tags = []string{tag} } - return h.service(service, tags, passingOnly, q, false) + 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, false) + return h.service(service, tags, passingOnly, q, serviceHealth) } // Connect is equivalent to Service except that it will only return services @@ -286,18 +292,31 @@ func (h *Health) Connect(service, tag string, passingOnly bool, q *QueryOptions) if tag != "" { tags = []string{tag} } - return h.service(service, tags, passingOnly, q, true) + 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, true) + return h.service(service, tags, passingOnly, q, connectHealth) } -func (h *Health) service(service string, tags []string, passingOnly bool, q *QueryOptions, connect bool) ([]*ServiceEntry, *QueryMeta, error) { - path := "/v1/health/service/" + service - if connect { +// 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 { diff --git a/vendor/github.com/hashicorp/consul/api/operator_license.go b/vendor/github.com/hashicorp/consul/api/operator_license.go index 25aa702e8..51b64cef4 100644 --- a/vendor/github.com/hashicorp/consul/api/operator_license.go +++ b/vendor/github.com/hashicorp/consul/api/operator_license.go @@ -36,6 +36,9 @@ type License struct { // 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"` } diff --git a/vendor/github.com/hashicorp/consul/api/operator_raft.go b/vendor/github.com/hashicorp/consul/api/operator_raft.go index a9844df2d..c6d7165d4 100644 --- a/vendor/github.com/hashicorp/consul/api/operator_raft.go +++ b/vendor/github.com/hashicorp/consul/api/operator_raft.go @@ -60,7 +60,7 @@ func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) err r := op.c.newRequest("DELETE", "/v1/operator/raft/peer") r.setWriteOptions(q) - r.params.Set("address", string(address)) + r.params.Set("address", address) _, resp, err := requireOK(op.c.doRequest(r)) if err != nil { @@ -77,7 +77,7 @@ 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", string(id)) + r.params.Set("id", id) _, resp, err := requireOK(op.c.doRequest(r)) if err != nil { diff --git a/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_darwin.go b/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_darwin.go new file mode 100644 index 000000000..2449041c5 --- /dev/null +++ b/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_darwin.go @@ -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) +} diff --git a/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_fallback.go b/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_fallback.go index 740791cc8..4e3e2b386 100644 --- a/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_fallback.go +++ b/vendor/github.com/hashicorp/consul/sdk/freeport/ephemeral_fallback.go @@ -1,4 +1,4 @@ -//+build !linux +//+build !linux,!darwin package freeport diff --git a/vendor/github.com/hashicorp/consul/sdk/freeport/freeport.go b/vendor/github.com/hashicorp/consul/sdk/freeport/freeport.go index 4ddc93737..eab12a87f 100644 --- a/vendor/github.com/hashicorp/consul/sdk/freeport/freeport.go +++ b/vendor/github.com/hashicorp/consul/sdk/freeport/freeport.go @@ -66,6 +66,14 @@ var ( // 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. @@ -108,16 +116,36 @@ func initialize() { } total = freePorts.Len() - go checkFreedPorts() + 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() - logf("INFO", "resetting the freeport package state") - effectiveMaxBlocks = 0 firstPort = 0 if lockLn != nil { @@ -132,11 +160,18 @@ func reset() { total = 0 } -func checkFreedPorts() { +func checkFreedPorts(stopCh <-chan struct{}) { + defer stopWg.Done() + ticker := time.NewTicker(250 * time.Millisecond) for { - <-ticker.C - checkFreedPortsOnce() + select { + case <-stopCh: + logf("INFO", "Closing checkFreedPorts()") + return + case <-ticker.C: + checkFreedPortsOnce() + } } } diff --git a/vendor/github.com/hashicorp/consul/sdk/testutil/assertions.go b/vendor/github.com/hashicorp/consul/sdk/testutil/assertions.go new file mode 100644 index 000000000..146e9f7fc --- /dev/null +++ b/vendor/github.com/hashicorp/consul/sdk/testutil/assertions.go @@ -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) + } +} diff --git a/vendor/github.com/hashicorp/consul/sdk/testutil/server.go b/vendor/github.com/hashicorp/consul/sdk/testutil/server.go index 66c7f43f9..a80f4cea1 100644 --- a/vendor/github.com/hashicorp/consul/sdk/testutil/server.go +++ b/vendor/github.com/hashicorp/consul/sdk/testutil/server.go @@ -88,7 +88,6 @@ type TestServerConfig struct { ACLDatacenter string `json:"acl_datacenter,omitempty"` PrimaryDatacenter string `json:"primary_datacenter,omitempty"` ACLDefaultPolicy string `json:"acl_default_policy,omitempty"` - ACLEnforceVersion8 bool `json:"acl_enforce_version_8"` ACL TestACLs `json:"acl,omitempty"` Encrypt string `json:"encrypt,omitempty"` CAFile string `json:"ca_file,omitempty"` @@ -381,7 +380,8 @@ func (s *TestServer) waitForAPI() error { for !time.Now().After(deadline) { time.Sleep(timer.Wait) - resp, err := s.HTTPClient.Get(s.url("/v1/agent/self")) + url := s.url("/v1/agent/self") + resp, err := s.masterGet(url) if err != nil { failed = true continue @@ -407,7 +407,7 @@ 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.HTTPClient.Get(url) + resp, err := s.masterGet(url) if err != nil { r.Fatalf("failed http get '%s': %v", url, err) } @@ -443,7 +443,7 @@ func (s *TestServer) WaitForActiveCARoot(t *testing.T) { 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.HTTPClient.Get(url) + resp, err := s.masterGet(url) if err != nil { r.Fatalf("failed http get '%s': %v", url, err) } @@ -475,7 +475,7 @@ 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.HTTPClient.Get(url) + resp, err := s.masterGet(url) if err != nil { r.Fatal("failed http get", err) } @@ -496,7 +496,7 @@ func (s *TestServer) WaitForSerfCheck(t *testing.T) { // Ensure the serfHealth check is registered url = s.url(fmt.Sprintf("/v1/health/node/%s", payload[0]["Node"])) - resp, err = s.HTTPClient.Get(url) + resp, err = s.masterGet(url) if err != nil { r.Fatal("failed http get", err) } @@ -521,3 +521,14 @@ func (s *TestServer) WaitForSerfCheck(t *testing.T) { } }) } + +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) +} diff --git a/vendor/github.com/hashicorp/go-multierror/README.md b/vendor/github.com/hashicorp/go-multierror/README.md index ead5830f7..e92fa614c 100644 --- a/vendor/github.com/hashicorp/go-multierror/README.md +++ b/vendor/github.com/hashicorp/go-multierror/README.md @@ -14,9 +14,10 @@ be a list of errors. If the caller knows this, they can unwrap the list and access the errors. If the caller doesn't know, the error formats to a nice human-readable format. -`go-multierror` implements the -[errwrap](https://github.com/hashicorp/errwrap) interface so that it can -be used with that library, as well. +`go-multierror` is fully compatible with the Go standard library +[errors](https://golang.org/pkg/errors/) package, including the +functions `As`, `Is`, and `Unwrap`. This provides a standardized approach +for introspecting on error values. ## Installation and Docs @@ -81,6 +82,39 @@ if err := something(); err != nil { } ``` +You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap) +function. This will continue to unwrap into subsequent errors until none exist. + +**Extracting an error** + +The standard library [`errors.As`](https://golang.org/pkg/errors/#As) +function can be used directly with a multierror to extract a specific error: + +```go +// Assume err is a multierror value +err := somefunc() + +// We want to know if "err" has a "RichErrorType" in it and extract it. +var errRich RichErrorType +if errors.As(err, &errRich) { + // It has it, and now errRich is populated. +} +``` + +**Checking for an exact error value** + +Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables) +error in the `os` package. You can check if this error is present by using +the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function. + +```go +// Assume err is a multierror value +err := somefunc() +if errors.Is(err, os.ErrNotExist) { + // err contains os.ErrNotExist +} +``` + **Returning a multierror only if there are errors** If you build a `multierror.Error`, you can use the `ErrorOrNil` function diff --git a/vendor/github.com/hashicorp/go-multierror/go.mod b/vendor/github.com/hashicorp/go-multierror/go.mod index 2534331d5..0afe8e6f9 100644 --- a/vendor/github.com/hashicorp/go-multierror/go.mod +++ b/vendor/github.com/hashicorp/go-multierror/go.mod @@ -1,3 +1,5 @@ module github.com/hashicorp/go-multierror +go 1.14 + require github.com/hashicorp/errwrap v1.0.0 diff --git a/vendor/github.com/hashicorp/go-multierror/multierror.go b/vendor/github.com/hashicorp/go-multierror/multierror.go index 89b1422d1..d05dd9269 100644 --- a/vendor/github.com/hashicorp/go-multierror/multierror.go +++ b/vendor/github.com/hashicorp/go-multierror/multierror.go @@ -1,6 +1,7 @@ package multierror import ( + "errors" "fmt" ) @@ -49,3 +50,69 @@ func (e *Error) GoString() string { func (e *Error) WrappedErrors() []error { return e.Errors } + +// Unwrap returns an error from Error (or nil if there are no errors). +// This error returned will further support Unwrap to get the next error, +// etc. The order will match the order of Errors in the multierror.Error +// at the time of calling. +// +// The resulting error supports errors.As/Is/Unwrap so you can continue +// to use the stdlib errors package to introspect further. +// +// This will perform a shallow copy of the errors slice. Any errors appended +// to this error after calling Unwrap will not be available until a new +// Unwrap is called on the multierror.Error. +func (e *Error) Unwrap() error { + // If we have no errors then we do nothing + if e == nil || len(e.Errors) == 0 { + return nil + } + + // If we have exactly one error, we can just return that directly. + if len(e.Errors) == 1 { + return e.Errors[0] + } + + // Shallow copy the slice + errs := make([]error, len(e.Errors)) + copy(errs, e.Errors) + return chain(errs) +} + +// chain implements the interfaces necessary for errors.Is/As/Unwrap to +// work in a deterministic way with multierror. A chain tracks a list of +// errors while accounting for the current represented error. This lets +// Is/As be meaningful. +// +// Unwrap returns the next error. In the cleanest form, Unwrap would return +// the wrapped error here but we can't do that if we want to properly +// get access to all the errors. Instead, users are recommended to use +// Is/As to get the correct error type out. +// +// Precondition: []error is non-empty (len > 0) +type chain []error + +// Error implements the error interface +func (e chain) Error() string { + return e[0].Error() +} + +// Unwrap implements errors.Unwrap by returning the next error in the +// chain or nil if there are no more errors. +func (e chain) Unwrap() error { + if len(e) == 1 { + return nil + } + + return e[1:] +} + +// As implements errors.As by attempting to map to the current value. +func (e chain) As(target interface{}) bool { + return errors.As(e[0], target) +} + +// Is implements errors.Is by comparing the current value directly. +func (e chain) Is(target error) bool { + return errors.Is(e[0], target) +} diff --git a/vendor/github.com/hashicorp/memberlist/config.go b/vendor/github.com/hashicorp/memberlist/config.go index c9cd17644..31099e75f 100644 --- a/vendor/github.com/hashicorp/memberlist/config.go +++ b/vendor/github.com/hashicorp/memberlist/config.go @@ -1,10 +1,15 @@ package memberlist import ( + "fmt" "io" "log" + "net" "os" + "strings" "time" + + multierror "github.com/hashicorp/go-multierror" ) type Config struct { @@ -116,6 +121,10 @@ type Config struct { // indirect UDP pings. DisableTcpPings bool + // DisableTcpPingsForNode is like DisableTcpPings, but lets you control + // whether to perform TCP pings on a node-by-node basis. + DisableTcpPingsForNode func(nodeName string) bool + // AwarenessMaxMultiplier will increase the probe interval if the node // becomes aware that it might be degraded and not meeting the soft real // time requirements to reliably probe other nodes. @@ -220,6 +229,39 @@ type Config struct { // reclaimed by one with a different address or port. By default, this is 0, // meaning nodes cannot be reclaimed this way. DeadNodeReclaimTime time.Duration + + // RequireNodeNames controls if the name of a node is required when sending + // a message to that node. + RequireNodeNames bool + // CIDRsAllowed If nil, allow any connection (default), otherwise specify all networks + // allowed to connect (you must specify IPv6/IPv4 separately) + // Using [] will block all connections. + CIDRsAllowed []net.IPNet +} + +// ParseCIDRs return a possible empty list of all Network that have been parsed +// In case of error, it returns succesfully parsed CIDRs and the last error found +func ParseCIDRs(v []string) ([]net.IPNet, error) { + nets := make([]net.IPNet, 0) + if v == nil { + return nets, nil + } + var errs error + hasErrors := false + for _, p := range v { + _, net, err := net.ParseCIDR(strings.TrimSpace(p)) + if err != nil { + err = fmt.Errorf("invalid cidr: %s", p) + errs = multierror.Append(errs, err) + hasErrors = true + } else { + nets = append(nets, *net) + } + } + if !hasErrors { + errs = nil + } + return nets, errs } // DefaultLANConfig returns a sane set of configurations for Memberlist. @@ -263,6 +305,7 @@ func DefaultLANConfig() *Config { HandoffQueueDepth: 1024, UDPBufferSize: 1400, + CIDRsAllowed: nil, // same as allow all } } @@ -282,6 +325,24 @@ func DefaultWANConfig() *Config { return conf } +// IPMustBeChecked return true if IPAllowed must be called +func (c *Config) IPMustBeChecked() bool { + return len(c.CIDRsAllowed) > 0 +} + +// IPAllowed return an error if access to memberlist is denied +func (c *Config) IPAllowed(ip net.IP) error { + if !c.IPMustBeChecked() { + return nil + } + for _, n := range c.CIDRsAllowed { + if n.Contains(ip) { + return nil + } + } + return fmt.Errorf("%s is not allowed", ip) +} + // DefaultLocalConfig works like DefaultConfig, however it returns a configuration // that is optimized for a local loopback environments. The default configuration is // still very conservative and errs on the side of caution. diff --git a/vendor/github.com/hashicorp/memberlist/go.mod b/vendor/github.com/hashicorp/memberlist/go.mod index d1b08f1fe..1b83a4f28 100644 --- a/vendor/github.com/hashicorp/memberlist/go.mod +++ b/vendor/github.com/hashicorp/memberlist/go.mod @@ -10,13 +10,9 @@ require ( github.com/hashicorp/go-msgpack v0.5.3 github.com/hashicorp/go-multierror v1.0.0 github.com/hashicorp/go-sockaddr v1.0.0 - github.com/miekg/dns v1.0.14 + github.com/miekg/dns v1.1.26 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 github.com/stretchr/testify v1.2.2 - golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3 // indirect - golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 // indirect - golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect - golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5 // indirect ) diff --git a/vendor/github.com/hashicorp/memberlist/go.sum b/vendor/github.com/hashicorp/memberlist/go.sum index 39534ac2f..15d34bfc6 100644 --- a/vendor/github.com/hashicorp/memberlist/go.sum +++ b/vendor/github.com/hashicorp/memberlist/go.sum @@ -18,8 +18,8 @@ github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCS github.com/hashicorp/go-uuid v1.0.0/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/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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -28,11 +28,21 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -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/net v0.0.0-20181023162649-9b4f9f5ad519 h1:x6rhz8Y9CjbgQkccRGmELH6K+LJj7tOoh3XWeC1yaQM= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -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/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/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-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-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-20190215142949-d0b11bdaac8a/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 h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/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= diff --git a/vendor/github.com/hashicorp/memberlist/logging.go b/vendor/github.com/hashicorp/memberlist/logging.go index f31acfb2f..2ca2bab4e 100644 --- a/vendor/github.com/hashicorp/memberlist/logging.go +++ b/vendor/github.com/hashicorp/memberlist/logging.go @@ -13,6 +13,14 @@ func LogAddress(addr net.Addr) string { return fmt.Sprintf("from=%s", addr.String()) } +func LogStringAddress(addr string) string { + if addr == "" { + return "from=" + } + + return fmt.Sprintf("from=%s", addr) +} + func LogConn(conn net.Conn) string { if conn == nil { return LogAddress(nil) diff --git a/vendor/github.com/hashicorp/memberlist/memberlist.go b/vendor/github.com/hashicorp/memberlist/memberlist.go index b34429c04..7ee040091 100644 --- a/vendor/github.com/hashicorp/memberlist/memberlist.go +++ b/vendor/github.com/hashicorp/memberlist/memberlist.go @@ -16,6 +16,7 @@ package memberlist import ( "container/list" + "errors" "fmt" "log" "net" @@ -31,12 +32,18 @@ import ( "github.com/miekg/dns" ) +var errNodeNamesAreRequired = errors.New("memberlist: node names are required by configuration but one was not provided") + type Memberlist struct { sequenceNum uint32 // Local sequence number incarnation uint32 // Local incarnation number numNodes uint32 // Number of known nodes (estimate) pushPullReq uint32 // Number of push/pull requests + advertiseLock sync.RWMutex + advertiseAddr net.IP + advertisePort uint16 + config *Config shutdown int32 // Used as an atomic boolean value shutdownCh chan struct{} @@ -46,7 +53,7 @@ type Memberlist struct { shutdownLock sync.Mutex // Serializes calls to Shutdown leaveLock sync.Mutex // Serializes calls to Leave - transport Transport + transport NodeAwareTransport handoffCh chan struct{} highPriorityMsgQueue *list.List @@ -174,11 +181,17 @@ func newMemberlist(conf *Config) (*Memberlist, error) { transport = nt } + nodeAwareTransport, ok := transport.(NodeAwareTransport) + if !ok { + logger.Printf("[DEBUG] memberlist: configured Transport is not a NodeAwareTransport and some features may not work as desired") + nodeAwareTransport = &shimNodeAwareTransport{transport} + } + m := &Memberlist{ config: conf, shutdownCh: make(chan struct{}), leaveBroadcast: make(chan struct{}, 1), - transport: transport, + transport: nodeAwareTransport, handoffCh: make(chan struct{}, 1), highPriorityMsgQueue: list.New(), lowPriorityMsgQueue: list.New(), @@ -192,6 +205,14 @@ func newMemberlist(conf *Config) (*Memberlist, error) { m.broadcasts.NumNodes = func() int { return m.estNumNodes() } + + // Get the final advertise address from the transport, which may need + // to see which address we bound to. We'll refresh this each time we + // send out an alive message. + if _, _, err := m.refreshAdvertise(); err != nil { + return nil, err + } + go m.streamListen() go m.packetListen() go m.packetHandler() @@ -239,7 +260,8 @@ func (m *Memberlist) Join(existing []string) (int, error) { for _, addr := range addrs { hp := joinHostPort(addr.ip.String(), addr.port) - if err := m.pushPullNode(hp, true); err != nil { + a := Address{Addr: hp, Name: addr.nodeName} + if err := m.pushPullNode(a, true); err != nil { err = fmt.Errorf("Failed to join %s: %v", addr.ip, err) errs = multierror.Append(errs, err) m.logger.Printf("[DEBUG] memberlist: %v", err) @@ -257,8 +279,9 @@ func (m *Memberlist) Join(existing []string) (int, error) { // ipPort holds information about a node we want to try to join. type ipPort struct { - ip net.IP - port uint16 + ip net.IP + port uint16 + nodeName string // optional } // tcpLookupIP is a helper to initiate a TCP-based DNS lookup for the given host. @@ -267,7 +290,7 @@ type ipPort struct { // Consul's. By doing the TCP lookup directly, we get the best chance for the // largest list of hosts to join. Since joins are relatively rare events, it's ok // to do this rather expensive operation. -func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16) ([]ipPort, error) { +func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16, nodeName string) ([]ipPort, error) { // Don't attempt any TCP lookups against non-fully qualified domain // names, since those will likely come from the resolv.conf file. if !strings.Contains(host, ".") { @@ -309,9 +332,9 @@ func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16) ([]ipPort, err for _, r := range in.Answer { switch rr := r.(type) { case (*dns.A): - ips = append(ips, ipPort{rr.A, defaultPort}) + ips = append(ips, ipPort{ip: rr.A, port: defaultPort, nodeName: nodeName}) case (*dns.AAAA): - ips = append(ips, ipPort{rr.AAAA, defaultPort}) + ips = append(ips, ipPort{ip: rr.AAAA, port: defaultPort, nodeName: nodeName}) case (*dns.CNAME): m.logger.Printf("[DEBUG] memberlist: Ignoring CNAME RR in TCP-first answer for '%s'", host) } @@ -325,6 +348,16 @@ func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16) ([]ipPort, err // resolveAddr is used to resolve the address into an address, // port, and error. If no port is given, use the default func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) { + // First peel off any leading node name. This is optional. + nodeName := "" + if slashIdx := strings.Index(hostStr, "/"); slashIdx >= 0 { + if slashIdx == 0 { + return nil, fmt.Errorf("empty node name provided") + } + nodeName = hostStr[0:slashIdx] + hostStr = hostStr[slashIdx+1:] + } + // This captures the supplied port, or the default one. hostStr = ensurePort(hostStr, m.config.BindPort) host, sport, err := net.SplitHostPort(hostStr) @@ -341,13 +374,15 @@ func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) { // will make sure the host part is in good shape for parsing, even for // IPv6 addresses. if ip := net.ParseIP(host); ip != nil { - return []ipPort{ipPort{ip, port}}, nil + return []ipPort{ + ipPort{ip: ip, port: port, nodeName: nodeName}, + }, nil } // First try TCP so we have the best chance for the largest list of // hosts to join. If this fails it's not fatal since this isn't a standard // way to query DNS, and we have a fallback below. - ips, err := m.tcpLookupIP(host, port) + ips, err := m.tcpLookupIP(host, port, nodeName) if err != nil { m.logger.Printf("[DEBUG] memberlist: TCP-first lookup failed for '%s', falling back to UDP: %s", hostStr, err) } @@ -364,7 +399,7 @@ func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) { } ips = make([]ipPort, 0, len(ans)) for _, ip := range ans { - ips = append(ips, ipPort{ip, port}) + ips = append(ips, ipPort{ip: ip, port: port, nodeName: nodeName}) } return ips, nil } @@ -375,10 +410,9 @@ func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) { func (m *Memberlist) setAlive() error { // Get the final advertise address from the transport, which may need // to see which address we bound to. - addr, port, err := m.transport.FinalAdvertiseAddr( - m.config.AdvertiseAddr, m.config.AdvertisePort) + addr, port, err := m.refreshAdvertise() if err != nil { - return fmt.Errorf("Failed to get final advertise address: %v", err) + return err } // Check if this is a public address without encryption @@ -414,9 +448,33 @@ func (m *Memberlist) setAlive() error { Vsn: m.config.BuildVsnArray(), } m.aliveNode(&a, nil, true) + return nil } +func (m *Memberlist) getAdvertise() (net.IP, uint16) { + m.advertiseLock.RLock() + defer m.advertiseLock.RUnlock() + return m.advertiseAddr, m.advertisePort +} + +func (m *Memberlist) setAdvertise(addr net.IP, port int) { + m.advertiseLock.Lock() + defer m.advertiseLock.Unlock() + m.advertiseAddr = addr + m.advertisePort = uint16(port) +} + +func (m *Memberlist) refreshAdvertise() (net.IP, int, error) { + addr, port, err := m.transport.FinalAdvertiseAddr( + m.config.AdvertiseAddr, m.config.AdvertisePort) + if err != nil { + return nil, 0, fmt.Errorf("Failed to get final advertise address: %v", err) + } + m.setAdvertise(addr, port) + return addr, port, nil +} + // LocalNode is used to return the local Node func (m *Memberlist) LocalNode() *Node { m.nodeLock.RLock() @@ -473,15 +531,20 @@ func (m *Memberlist) UpdateNode(timeout time.Duration) error { } // Deprecated: SendTo is deprecated in favor of SendBestEffort, which requires a node to -// target. +// target. If you don't have a node then use SendToAddress. func (m *Memberlist) SendTo(to net.Addr, msg []byte) error { + a := Address{Addr: to.String(), Name: ""} + return m.SendToAddress(a, msg) +} + +func (m *Memberlist) SendToAddress(a Address, msg []byte) error { // Encode as a user message buf := make([]byte, 1, len(msg)+1) buf[0] = byte(userMsg) buf = append(buf, msg...) // Send the message - return m.rawSendMsgPacket(to.String(), nil, buf) + return m.rawSendMsgPacket(a, nil, buf) } // Deprecated: SendToUDP is deprecated in favor of SendBestEffort. @@ -505,7 +568,8 @@ func (m *Memberlist) SendBestEffort(to *Node, msg []byte) error { buf = append(buf, msg...) // Send the message - return m.rawSendMsgPacket(to.Address(), to, buf) + a := Address{Addr: to.Address(), Name: to.Name} + return m.rawSendMsgPacket(a, to, buf) } // SendReliable uses the reliable stream-oriented interface of the transport to @@ -513,7 +577,7 @@ func (m *Memberlist) SendBestEffort(to *Node, msg []byte) error { // mechanism). Delivery is guaranteed if no error is returned, and there is no // limit on the size of the message. func (m *Memberlist) SendReliable(to *Node, msg []byte) error { - return m.sendUserMsg(to.Address(), msg) + return m.sendUserMsg(to.FullAddress(), msg) } // Members returns a list of all known live nodes. The node structures @@ -672,7 +736,7 @@ func (m *Memberlist) hasLeft() bool { return atomic.LoadInt32(&m.leave) == 1 } -func (m *Memberlist) getNodeState(addr string) nodeStateType { +func (m *Memberlist) getNodeState(addr string) NodeStateType { m.nodeLock.RLock() defer m.nodeLock.RUnlock() diff --git a/vendor/github.com/hashicorp/memberlist/mock_transport.go b/vendor/github.com/hashicorp/memberlist/mock_transport.go index b8bafa802..0a7d30a27 100644 --- a/vendor/github.com/hashicorp/memberlist/mock_transport.go +++ b/vendor/github.com/hashicorp/memberlist/mock_transport.go @@ -1,7 +1,9 @@ package memberlist import ( + "bytes" "fmt" + "io" "net" "strconv" "time" @@ -10,26 +12,33 @@ import ( // MockNetwork is used as a factory that produces MockTransport instances which // are uniquely addressed and wired up to talk to each other. type MockNetwork struct { - transports map[string]*MockTransport - port int + transportsByAddr map[string]*MockTransport + transportsByName map[string]*MockTransport + port int } // NewTransport returns a new MockTransport with a unique address, wired up to // talk to the other transports in the MockNetwork. -func (n *MockNetwork) NewTransport() *MockTransport { +func (n *MockNetwork) NewTransport(name string) *MockTransport { n.port += 1 addr := fmt.Sprintf("127.0.0.1:%d", n.port) transport := &MockTransport{ net: n, - addr: &MockAddress{addr}, + addr: &MockAddress{addr, name}, packetCh: make(chan *Packet), streamCh: make(chan net.Conn), } - if n.transports == nil { - n.transports = make(map[string]*MockTransport) + if n.transportsByAddr == nil { + n.transportsByAddr = make(map[string]*MockTransport) } - n.transports[addr] = transport + n.transportsByAddr[addr] = transport + + if n.transportsByName == nil { + n.transportsByName = make(map[string]*MockTransport) + } + n.transportsByName[name] = transport + return transport } @@ -37,6 +46,7 @@ func (n *MockNetwork) NewTransport() *MockTransport { // address scheme. type MockAddress struct { addr string + name string } // See net.Addr. @@ -57,6 +67,8 @@ type MockTransport struct { streamCh chan net.Conn } +var _ NodeAwareTransport = (*MockTransport)(nil) + // See Transport. func (t *MockTransport) FinalAdvertiseAddr(string, int) (net.IP, int, error) { host, portStr, err := net.SplitHostPort(t.addr.String()) @@ -79,9 +91,15 @@ func (t *MockTransport) FinalAdvertiseAddr(string, int) (net.IP, int, error) { // See Transport. func (t *MockTransport) WriteTo(b []byte, addr string) (time.Time, error) { - dest, ok := t.net.transports[addr] - if !ok { - return time.Time{}, fmt.Errorf("No route to %q", addr) + a := Address{Addr: addr, Name: ""} + return t.WriteToAddress(b, a) +} + +// See NodeAwareTransport. +func (t *MockTransport) WriteToAddress(b []byte, a Address) (time.Time, error) { + dest, err := t.getPeer(a) + if err != nil { + return time.Time{}, err } now := time.Now() @@ -98,11 +116,45 @@ func (t *MockTransport) PacketCh() <-chan *Packet { return t.packetCh } +// See NodeAwareTransport. +func (t *MockTransport) IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error { + if shouldClose { + defer conn.Close() + } + + // Copy everything from the stream into packet buffer. + var buf bytes.Buffer + if _, err := io.Copy(&buf, conn); err != nil { + return fmt.Errorf("failed to read packet: %v", err) + } + + // Check the length - it needs to have at least one byte to be a proper + // message. This is checked elsewhere for writes coming in directly from + // the UDP socket. + if n := buf.Len(); n < 1 { + return fmt.Errorf("packet too short (%d bytes) %s", n, LogAddress(addr)) + } + + // Inject the packet. + t.packetCh <- &Packet{ + Buf: buf.Bytes(), + From: addr, + Timestamp: now, + } + return nil +} + // See Transport. func (t *MockTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) { - dest, ok := t.net.transports[addr] - if !ok { - return nil, fmt.Errorf("No route to %q", addr) + a := Address{Addr: addr, Name: ""} + return t.DialAddressTimeout(a, timeout) +} + +// See NodeAwareTransport. +func (t *MockTransport) DialAddressTimeout(a Address, timeout time.Duration) (net.Conn, error) { + dest, err := t.getPeer(a) + if err != nil { + return nil, err } p1, p2 := net.Pipe() @@ -115,7 +167,29 @@ func (t *MockTransport) StreamCh() <-chan net.Conn { return t.streamCh } +// See NodeAwareTransport. +func (t *MockTransport) IngestStream(conn net.Conn) error { + t.streamCh <- conn + return nil +} + // See Transport. func (t *MockTransport) Shutdown() error { return nil } + +func (t *MockTransport) getPeer(a Address) (*MockTransport, error) { + var ( + dest *MockTransport + ok bool + ) + if a.Name != "" { + dest, ok = t.net.transportsByName[a.Name] + } else { + dest, ok = t.net.transportsByAddr[a.Addr] + } + if !ok { + return nil, fmt.Errorf("No route to %s", a) + } + return dest, nil +} diff --git a/vendor/github.com/hashicorp/memberlist/net.go b/vendor/github.com/hashicorp/memberlist/net.go index ddeea9bc1..8d1d7271e 100644 --- a/vendor/github.com/hashicorp/memberlist/net.go +++ b/vendor/github.com/hashicorp/memberlist/net.go @@ -84,15 +84,28 @@ type ping struct { // the intended recipient. This is to protect again an agent // restart with a new name. Node string + + SourceAddr []byte `codec:",omitempty"` // Source address, used for a direct reply + SourcePort uint16 `codec:",omitempty"` // Source port, used for a direct reply + SourceNode string `codec:",omitempty"` // Source name, used for a direct reply } -// indirect ping sent to an indirect ndoe +// indirect ping sent to an indirect node type indirectPingReq struct { SeqNo uint32 Target []byte Port uint16 - Node string - Nack bool // true if we'd like a nack back + + // Node is sent so the target can verify they are + // the intended recipient. This is to protect against an agent + // restart with a new name. + Node string + + Nack bool // true if we'd like a nack back + + SourceAddr []byte `codec:",omitempty"` // Source address, used for a direct reply + SourcePort uint16 `codec:",omitempty"` // Source port, used for a direct reply + SourceNode string `codec:",omitempty"` // Source name, used for a direct reply } // ack response is sent for a ping @@ -163,7 +176,7 @@ type pushNodeState struct { Port uint16 Meta []byte Incarnation uint32 - State nodeStateType + State NodeStateType Vsn []uint8 // Protocol versions } @@ -207,9 +220,9 @@ func (m *Memberlist) streamListen() { // handleConn handles a single incoming stream connection from the transport. func (m *Memberlist) handleConn(conn net.Conn) { + defer conn.Close() m.logger.Printf("[DEBUG] memberlist: Stream connection %s", LogConn(conn)) - defer conn.Close() metrics.IncrCounter([]string{"memberlist", "tcp", "accept"}, 1) conn.SetDeadline(time.Now().Add(m.config.TCPTimeout)) @@ -483,7 +496,19 @@ func (m *Memberlist) handlePing(buf []byte, from net.Addr) { if m.config.Ping != nil { ack.Payload = m.config.Ping.AckPayload() } - if err := m.encodeAndSendMsg(from.String(), ackRespMsg, &ack); err != nil { + + addr := "" + if len(p.SourceAddr) > 0 && p.SourcePort > 0 { + addr = joinHostPort(net.IP(p.SourceAddr).String(), p.SourcePort) + } else { + addr = from.String() + } + + a := Address{ + Addr: addr, + Name: p.SourceNode, + } + if err := m.encodeAndSendMsg(a, ackRespMsg, &ack); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send ack: %s %s", err, LogAddress(from)) } } @@ -503,7 +528,25 @@ func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) { // Send a ping to the correct host. localSeqNo := m.nextSeqNo() - ping := ping{SeqNo: localSeqNo, Node: ind.Node} + selfAddr, selfPort := m.getAdvertise() + ping := ping{ + SeqNo: localSeqNo, + Node: ind.Node, + // The outbound message is addressed FROM us. + SourceAddr: selfAddr, + SourcePort: selfPort, + SourceNode: m.config.Name, + } + + // Forward the ack back to the requestor. If the request encodes an origin + // use that otherwise assume that the other end of the UDP socket is + // usable. + indAddr := "" + if len(ind.SourceAddr) > 0 && ind.SourcePort > 0 { + indAddr = joinHostPort(net.IP(ind.SourceAddr).String(), ind.SourcePort) + } else { + indAddr = from.String() + } // Setup a response handler to relay the ack cancelCh := make(chan struct{}) @@ -511,18 +554,25 @@ func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) { // Try to prevent the nack if we've caught it in time. close(cancelCh) - // Forward the ack back to the requestor. ack := ackResp{ind.SeqNo, nil} - if err := m.encodeAndSendMsg(from.String(), ackRespMsg, &ack); err != nil { - m.logger.Printf("[ERR] memberlist: Failed to forward ack: %s %s", err, LogAddress(from)) + a := Address{ + Addr: indAddr, + Name: ind.SourceNode, + } + if err := m.encodeAndSendMsg(a, ackRespMsg, &ack); err != nil { + m.logger.Printf("[ERR] memberlist: Failed to forward ack: %s %s", err, LogStringAddress(indAddr)) } } m.setAckHandler(localSeqNo, respHandler, m.config.ProbeTimeout) // Send the ping. addr := joinHostPort(net.IP(ind.Target).String(), ind.Port) - if err := m.encodeAndSendMsg(addr, pingMsg, &ping); err != nil { - m.logger.Printf("[ERR] memberlist: Failed to send indirect ping: %s %s", err, LogAddress(from)) + a := Address{ + Addr: addr, + Name: ind.Node, + } + if err := m.encodeAndSendMsg(a, pingMsg, &ping); err != nil { + m.logger.Printf("[ERR] memberlist: Failed to send indirect ping: %s %s", err, LogStringAddress(indAddr)) } // Setup a timer to fire off a nack if no ack is seen in time. @@ -533,8 +583,12 @@ func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) { return case <-time.After(m.config.ProbeTimeout): nack := nackResp{ind.SeqNo} - if err := m.encodeAndSendMsg(from.String(), nackRespMsg, &nack); err != nil { - m.logger.Printf("[ERR] memberlist: Failed to send nack: %s %s", err, LogAddress(from)) + a := Address{ + Addr: indAddr, + Name: ind.SourceNode, + } + if err := m.encodeAndSendMsg(a, nackRespMsg, &nack); err != nil { + m.logger.Printf("[ERR] memberlist: Failed to send nack: %s %s", err, LogStringAddress(indAddr)) } } }() @@ -568,12 +622,47 @@ func (m *Memberlist) handleSuspect(buf []byte, from net.Addr) { m.suspectNode(&sus) } +// ensureCanConnect return the IP from a RemoteAddress +// return error if this client must not connect +func (m *Memberlist) ensureCanConnect(from net.Addr) error { + if !m.config.IPMustBeChecked() { + return nil + } + source := from.String() + if source == "pipe" { + return nil + } + host, _, err := net.SplitHostPort(source) + if err != nil { + return err + } + + ip := net.ParseIP(host) + if ip == nil { + return fmt.Errorf("Cannot parse IP from %s", host) + } + return m.config.IPAllowed(ip) +} + func (m *Memberlist) handleAlive(buf []byte, from net.Addr) { + if err := m.ensureCanConnect(from); err != nil { + m.logger.Printf("[DEBUG] memberlist: Blocked alive message: %s %s", err, LogAddress(from)) + return + } var live alive if err := decode(buf, &live); err != nil { m.logger.Printf("[ERR] memberlist: Failed to decode alive message: %s %s", err, LogAddress(from)) return } + if m.config.IPMustBeChecked() { + innerIP := net.IP(live.Addr) + if innerIP != nil { + if err := m.config.IPAllowed(innerIP); err != nil { + m.logger.Printf("[DEBUG] memberlist: Blocked alive.Addr=%s message from: %s %s", innerIP.String(), err, LogAddress(from)) + return + } + } + } // For proto versions < 2, there is no port provided. Mask old // behavior by using the configured port @@ -615,12 +704,12 @@ func (m *Memberlist) handleCompressed(buf []byte, from net.Addr, timestamp time. } // encodeAndSendMsg is used to combine the encoding and sending steps -func (m *Memberlist) encodeAndSendMsg(addr string, msgType messageType, msg interface{}) error { +func (m *Memberlist) encodeAndSendMsg(a Address, msgType messageType, msg interface{}) error { out, err := encode(msgType, msg) if err != nil { return err } - if err := m.sendMsg(addr, out.Bytes()); err != nil { + if err := m.sendMsg(a, out.Bytes()); err != nil { return err } return nil @@ -628,7 +717,7 @@ func (m *Memberlist) encodeAndSendMsg(addr string, msgType messageType, msg inte // sendMsg is used to send a message via packet to another host. It will // opportunistically create a compoundMsg and piggy back other broadcasts. -func (m *Memberlist) sendMsg(addr string, msg []byte) error { +func (m *Memberlist) sendMsg(a Address, msg []byte) error { // Check if we can piggy back any messages bytesAvail := m.config.UDPBufferSize - len(msg) - compoundHeaderOverhead if m.config.EncryptionEnabled() && m.config.GossipVerifyOutgoing { @@ -638,7 +727,7 @@ func (m *Memberlist) sendMsg(addr string, msg []byte) error { // Fast path if nothing to piggypack if len(extra) == 0 { - return m.rawSendMsgPacket(addr, nil, msg) + return m.rawSendMsgPacket(a, nil, msg) } // Join all the messages @@ -650,12 +739,16 @@ func (m *Memberlist) sendMsg(addr string, msg []byte) error { compound := makeCompoundMessage(msgs) // Send the message - return m.rawSendMsgPacket(addr, nil, compound.Bytes()) + return m.rawSendMsgPacket(a, nil, compound.Bytes()) } // rawSendMsgPacket is used to send message via packet to another host without // modification, other than compression or encryption if enabled. -func (m *Memberlist) rawSendMsgPacket(addr string, node *Node, msg []byte) error { +func (m *Memberlist) rawSendMsgPacket(a Address, node *Node, msg []byte) error { + if a.Name == "" && m.config.RequireNodeNames { + return errNodeNamesAreRequired + } + // Check if we have compression enabled if m.config.EnableCompression { buf, err := compressPayload(msg) @@ -672,9 +765,9 @@ func (m *Memberlist) rawSendMsgPacket(addr string, node *Node, msg []byte) error // Try to look up the destination node. Note this will only work if the // bare ip address is used as the node name, which is not guaranteed. if node == nil { - toAddr, _, err := net.SplitHostPort(addr) + toAddr, _, err := net.SplitHostPort(a.Addr) if err != nil { - m.logger.Printf("[ERR] memberlist: Failed to parse address %q: %v", addr, err) + m.logger.Printf("[ERR] memberlist: Failed to parse address %q: %v", a.Addr, err) return err } m.nodeLock.RLock() @@ -709,14 +802,14 @@ func (m *Memberlist) rawSendMsgPacket(addr string, node *Node, msg []byte) error } metrics.IncrCounter([]string{"memberlist", "udp", "sent"}, float32(len(msg))) - _, err := m.transport.WriteTo(msg, addr) + _, err := m.transport.WriteToAddress(msg, a) return err } // rawSendMsgStream is used to stream a message to another host without // modification, other than applying compression and encryption if enabled. func (m *Memberlist) rawSendMsgStream(conn net.Conn, sendBuf []byte) error { - // Check if compresion is enabled + // Check if compression is enabled if m.config.EnableCompression { compBuf, err := compressPayload(sendBuf) if err != nil { @@ -749,8 +842,12 @@ func (m *Memberlist) rawSendMsgStream(conn net.Conn, sendBuf []byte) error { } // sendUserMsg is used to stream a user message to another host. -func (m *Memberlist) sendUserMsg(addr string, sendBuf []byte) error { - conn, err := m.transport.DialTimeout(addr, m.config.TCPTimeout) +func (m *Memberlist) sendUserMsg(a Address, sendBuf []byte) error { + if a.Name == "" && m.config.RequireNodeNames { + return errNodeNamesAreRequired + } + + conn, err := m.transport.DialAddressTimeout(a, m.config.TCPTimeout) if err != nil { return err } @@ -775,14 +872,18 @@ func (m *Memberlist) sendUserMsg(addr string, sendBuf []byte) error { // sendAndReceiveState is used to initiate a push/pull over a stream with a // remote host. -func (m *Memberlist) sendAndReceiveState(addr string, join bool) ([]pushNodeState, []byte, error) { +func (m *Memberlist) sendAndReceiveState(a Address, join bool) ([]pushNodeState, []byte, error) { + if a.Name == "" && m.config.RequireNodeNames { + return nil, nil, errNodeNamesAreRequired + } + // Attempt to connect - conn, err := m.transport.DialTimeout(addr, m.config.TCPTimeout) + conn, err := m.transport.DialAddressTimeout(a, m.config.TCPTimeout) if err != nil { return nil, nil, err } defer conn.Close() - m.logger.Printf("[DEBUG] memberlist: Initiating push/pull sync with: %s", conn.RemoteAddr()) + m.logger.Printf("[DEBUG] memberlist: Initiating push/pull sync with: %s %s", a.Name, conn.RemoteAddr()) metrics.IncrCounter([]string{"memberlist", "tcp", "connect"}, 1) // Send our state @@ -1047,16 +1148,17 @@ func (m *Memberlist) mergeRemoteState(join bool, remoteNodes []pushNodeState, us nodes := make([]*Node, len(remoteNodes)) for idx, n := range remoteNodes { nodes[idx] = &Node{ - Name: n.Name, - Addr: n.Addr, - Port: n.Port, - Meta: n.Meta, - PMin: n.Vsn[0], - PMax: n.Vsn[1], - PCur: n.Vsn[2], - DMin: n.Vsn[3], - DMax: n.Vsn[4], - DCur: n.Vsn[5], + Name: n.Name, + Addr: n.Addr, + Port: n.Port, + Meta: n.Meta, + State: n.State, + PMin: n.Vsn[0], + PMax: n.Vsn[1], + PCur: n.Vsn[2], + DMin: n.Vsn[3], + DMax: n.Vsn[4], + DCur: n.Vsn[5], } } if err := m.config.Merge.NotifyMerge(nodes); err != nil { @@ -1109,8 +1211,12 @@ func (m *Memberlist) readUserMsg(bufConn io.Reader, dec *codec.Decoder) error { // a ping, and waits for an ack. All of this is done as a series of blocking // operations, given the deadline. The bool return parameter is true if we // we able to round trip a ping to the other node. -func (m *Memberlist) sendPingAndWaitForAck(addr string, ping ping, deadline time.Time) (bool, error) { - conn, err := m.transport.DialTimeout(addr, deadline.Sub(time.Now())) +func (m *Memberlist) sendPingAndWaitForAck(a Address, ping ping, deadline time.Time) (bool, error) { + if a.Name == "" && m.config.RequireNodeNames { + return false, errNodeNamesAreRequired + } + + conn, err := m.transport.DialAddressTimeout(a, deadline.Sub(time.Now())) if err != nil { // If the node is actually dead we expect this to fail, so we // shouldn't spam the logs with it. After this point, errors diff --git a/vendor/github.com/hashicorp/memberlist/net_transport.go b/vendor/github.com/hashicorp/memberlist/net_transport.go index 4723127f5..058301172 100644 --- a/vendor/github.com/hashicorp/memberlist/net_transport.go +++ b/vendor/github.com/hashicorp/memberlist/net_transport.go @@ -1,7 +1,9 @@ package memberlist import ( + "bytes" "fmt" + "io" "log" "net" "sync" @@ -48,6 +50,8 @@ type NetTransport struct { shutdown int32 } +var _ NodeAwareTransport = (*NetTransport)(nil) + // NewNetTransport returns a net transport with the given configuration. On // success all the network listeners will be created and listening. func NewNetTransport(config *NetTransportConfig) (*NetTransport, error) { @@ -170,6 +174,14 @@ func (t *NetTransport) FinalAdvertiseAddr(ip string, port int) (net.IP, int, err // See Transport. func (t *NetTransport) WriteTo(b []byte, addr string) (time.Time, error) { + a := Address{Addr: addr, Name: ""} + return t.WriteToAddress(b, a) +} + +// See NodeAwareTransport. +func (t *NetTransport) WriteToAddress(b []byte, a Address) (time.Time, error) { + addr := a.Addr + udpAddr, err := net.ResolveUDPAddr("udp", addr) if err != nil { return time.Time{}, err @@ -188,8 +200,44 @@ func (t *NetTransport) PacketCh() <-chan *Packet { return t.packetCh } +// See IngestionAwareTransport. +func (t *NetTransport) IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error { + if shouldClose { + defer conn.Close() + } + + // Copy everything from the stream into packet buffer. + var buf bytes.Buffer + if _, err := io.Copy(&buf, conn); err != nil { + return fmt.Errorf("failed to read packet: %v", err) + } + + // Check the length - it needs to have at least one byte to be a proper + // message. This is checked elsewhere for writes coming in directly from + // the UDP socket. + if n := buf.Len(); n < 1 { + return fmt.Errorf("packet too short (%d bytes) %s", n, LogAddress(addr)) + } + + // Inject the packet. + t.packetCh <- &Packet{ + Buf: buf.Bytes(), + From: addr, + Timestamp: now, + } + return nil +} + // See Transport. func (t *NetTransport) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) { + a := Address{Addr: addr, Name: ""} + return t.DialAddressTimeout(a, timeout) +} + +// See NodeAwareTransport. +func (t *NetTransport) DialAddressTimeout(a Address, timeout time.Duration) (net.Conn, error) { + addr := a.Addr + dialer := net.Dialer{Timeout: timeout} return dialer.Dial("tcp", addr) } @@ -199,6 +247,12 @@ func (t *NetTransport) StreamCh() <-chan net.Conn { return t.streamCh } +// See IngestionAwareTransport. +func (t *NetTransport) IngestStream(conn net.Conn) error { + t.streamCh <- conn + return nil +} + // See Transport. func (t *NetTransport) Shutdown() error { // This will avoid log spam about errors when we shut down. diff --git a/vendor/github.com/hashicorp/memberlist/security.go b/vendor/github.com/hashicorp/memberlist/security.go index d90114eb0..4cb4da36f 100644 --- a/vendor/github.com/hashicorp/memberlist/security.go +++ b/vendor/github.com/hashicorp/memberlist/security.go @@ -106,7 +106,10 @@ func encryptPayload(vsn encryptionVersion, key []byte, msg []byte, data []byte, dst.WriteByte(byte(vsn)) // Add a random nonce - io.CopyN(dst, rand.Reader, nonceSize) + _, err = io.CopyN(dst, rand.Reader, nonceSize) + if err != nil { + return err + } afterNonce := dst.Len() // Ensure we are correctly padded (only version 0) diff --git a/vendor/github.com/hashicorp/memberlist/state.go b/vendor/github.com/hashicorp/memberlist/state.go index bbb3c33e8..7044f293c 100644 --- a/vendor/github.com/hashicorp/memberlist/state.go +++ b/vendor/github.com/hashicorp/memberlist/state.go @@ -13,27 +13,28 @@ import ( metrics "github.com/armon/go-metrics" ) -type nodeStateType int +type NodeStateType int const ( - stateAlive nodeStateType = iota - stateSuspect - stateDead - stateLeft + StateAlive NodeStateType = iota + StateSuspect + StateDead + StateLeft ) // Node represents a node in the cluster. type Node struct { - Name string - Addr net.IP - Port uint16 - Meta []byte // Metadata from the delegate for this node. - PMin uint8 // Minimum protocol version this understands - PMax uint8 // Maximum protocol version this understands - PCur uint8 // Current version node is speaking - DMin uint8 // Min protocol version for the delegate to understand - DMax uint8 // Max protocol version for the delegate to understand - DCur uint8 // Current version delegate is speaking + Name string + Addr net.IP + Port uint16 + Meta []byte // Metadata from the delegate for this node. + State NodeStateType // State of the node. + PMin uint8 // Minimum protocol version this understands + PMax uint8 // Maximum protocol version this understands + PCur uint8 // Current version node is speaking + DMin uint8 // Min protocol version for the delegate to understand + DMax uint8 // Max protocol version for the delegate to understand + DCur uint8 // Current version delegate is speaking } // Address returns the host:port form of a node's address, suitable for use @@ -42,6 +43,15 @@ func (n *Node) Address() string { return joinHostPort(n.Addr.String(), n.Port) } +// FullAddress returns the node name and host:port form of a node's address, +// suitable for use with a transport. +func (n *Node) FullAddress() Address { + return Address{ + Addr: joinHostPort(n.Addr.String(), n.Port), + Name: n.Name, + } +} + // String returns the node name func (n *Node) String() string { return n.Name @@ -51,7 +61,7 @@ func (n *Node) String() string { type nodeState struct { Node Incarnation uint32 // Last known incarnation number - State nodeStateType // Current state + State NodeStateType // Current state StateChange time.Time // Time last state change happened } @@ -61,8 +71,14 @@ func (n *nodeState) Address() string { return n.Node.Address() } +// FullAddress returns the node name and host:port form of a node's address, +// suitable for use with a transport. +func (n *nodeState) FullAddress() Address { + return n.Node.FullAddress() +} + func (n *nodeState) DeadOrLeft() bool { - return n.State == stateDead || n.State == stateLeft + return n.State == StateDead || n.State == StateLeft } // ackHandler is used to register handlers for incoming acks and nacks. @@ -276,7 +292,14 @@ func (m *Memberlist) probeNode(node *nodeState) { } // Prepare a ping message and setup an ack handler. - ping := ping{SeqNo: m.nextSeqNo(), Node: node.Name} + selfAddr, selfPort := m.getAdvertise() + ping := ping{ + SeqNo: m.nextSeqNo(), + Node: node.Name, + SourceAddr: selfAddr, + SourcePort: selfPort, + SourceNode: m.config.Name, + } ackCh := make(chan ackMessage, m.config.IndirectChecks+1) nackCh := make(chan struct{}, m.config.IndirectChecks+1) m.setProbeChannels(ping.SeqNo, ackCh, nackCh, probeInterval) @@ -299,8 +322,8 @@ func (m *Memberlist) probeNode(node *nodeState) { defer func() { m.awareness.ApplyDelta(awarenessDelta) }() - if node.State == stateAlive { - if err := m.encodeAndSendMsg(addr, pingMsg, &ping); err != nil { + if node.State == StateAlive { + if err := m.encodeAndSendMsg(node.FullAddress(), pingMsg, &ping); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send ping: %s", err) if failedRemote(err) { goto HANDLE_REMOTE_FAILURE @@ -325,7 +348,7 @@ func (m *Memberlist) probeNode(node *nodeState) { } compound := makeCompoundMessage(msgs) - if err := m.rawSendMsgPacket(addr, &node.Node, compound.Bytes()); err != nil { + if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, compound.Bytes()); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send compound ping and suspect message to %s: %s", addr, err) if failedRemote(err) { goto HANDLE_REMOTE_FAILURE @@ -374,13 +397,22 @@ HANDLE_REMOTE_FAILURE: kNodes := kRandomNodes(m.config.IndirectChecks, m.nodes, func(n *nodeState) bool { return n.Name == m.config.Name || n.Name == node.Name || - n.State != stateAlive + n.State != StateAlive }) m.nodeLock.RUnlock() // Attempt an indirect ping. expectedNacks := 0 - ind := indirectPingReq{SeqNo: ping.SeqNo, Target: node.Addr, Port: node.Port, Node: node.Name} + selfAddr, selfPort = m.getAdvertise() + ind := indirectPingReq{ + SeqNo: ping.SeqNo, + Target: node.Addr, + Port: node.Port, + Node: node.Name, + SourceAddr: selfAddr, + SourcePort: selfPort, + SourceNode: m.config.Name, + } for _, peer := range kNodes { // We only expect nack to be sent from peers who understand // version 4 of the protocol. @@ -388,7 +420,7 @@ HANDLE_REMOTE_FAILURE: expectedNacks++ } - if err := m.encodeAndSendMsg(peer.Address(), indirectPingMsg, &ind); err != nil { + if err := m.encodeAndSendMsg(peer.FullAddress(), indirectPingMsg, &ind); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send indirect ping: %s", err) } } @@ -404,10 +436,13 @@ HANDLE_REMOTE_FAILURE: // which protocol version we are speaking. That's why we've included a // config option to turn this off if desired. fallbackCh := make(chan bool, 1) - if (!m.config.DisableTcpPings) && (node.PMax >= 3) { + + disableTcpPings := m.config.DisableTcpPings || + (m.config.DisableTcpPingsForNode != nil && m.config.DisableTcpPingsForNode(node.Name)) + if (!disableTcpPings) && (node.PMax >= 3) { go func() { defer close(fallbackCh) - didContact, err := m.sendPingAndWaitForAck(node.Address(), ping, deadline) + didContact, err := m.sendPingAndWaitForAck(node.FullAddress(), ping, deadline) if err != nil { m.logger.Printf("[ERR] memberlist: Failed fallback ping: %s", err) } else { @@ -464,12 +499,21 @@ HANDLE_REMOTE_FAILURE: // Ping initiates a ping to the node with the specified name. func (m *Memberlist) Ping(node string, addr net.Addr) (time.Duration, error) { // Prepare a ping message and setup an ack handler. - ping := ping{SeqNo: m.nextSeqNo(), Node: node} + selfAddr, selfPort := m.getAdvertise() + ping := ping{ + SeqNo: m.nextSeqNo(), + Node: node, + SourceAddr: selfAddr, + SourcePort: selfPort, + SourceNode: m.config.Name, + } ackCh := make(chan ackMessage, m.config.IndirectChecks+1) m.setProbeChannels(ping.SeqNo, ackCh, nil, m.config.ProbeInterval) + a := Address{Addr: addr.String(), Name: node} + // Send a ping to the node. - if err := m.encodeAndSendMsg(addr.String(), pingMsg, &ping); err != nil { + if err := m.encodeAndSendMsg(a, pingMsg, &ping); err != nil { return 0, err } @@ -530,10 +574,10 @@ func (m *Memberlist) gossip() { } switch n.State { - case stateAlive, stateSuspect: + case StateAlive, StateSuspect: return false - case stateDead: + case StateDead: return time.Since(n.StateChange) > m.config.GossipToTheDeadTime default: @@ -558,13 +602,13 @@ func (m *Memberlist) gossip() { addr := node.Address() if len(msgs) == 1 { // Send single message as is - if err := m.rawSendMsgPacket(addr, &node.Node, msgs[0]); err != nil { + if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, msgs[0]); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err) } } else { // Otherwise create and send a compound message compound := makeCompoundMessage(msgs) - if err := m.rawSendMsgPacket(addr, &node.Node, compound.Bytes()); err != nil { + if err := m.rawSendMsgPacket(node.FullAddress(), &node.Node, compound.Bytes()); err != nil { m.logger.Printf("[ERR] memberlist: Failed to send gossip to %s: %s", addr, err) } } @@ -580,7 +624,7 @@ func (m *Memberlist) pushPull() { m.nodeLock.RLock() nodes := kRandomNodes(1, m.nodes, func(n *nodeState) bool { return n.Name == m.config.Name || - n.State != stateAlive + n.State != StateAlive }) m.nodeLock.RUnlock() @@ -591,17 +635,17 @@ func (m *Memberlist) pushPull() { node := nodes[0] // Attempt a push pull - if err := m.pushPullNode(node.Address(), false); err != nil { + if err := m.pushPullNode(node.FullAddress(), false); err != nil { m.logger.Printf("[ERR] memberlist: Push/Pull with %s failed: %s", node.Name, err) } } // pushPullNode does a complete state exchange with a specific node. -func (m *Memberlist) pushPullNode(addr string, join bool) error { +func (m *Memberlist) pushPullNode(a Address, join bool) error { defer metrics.MeasureSince([]string{"memberlist", "pushPullNode"}, time.Now()) // Attempt to send and receive with the node - remote, userState, err := m.sendAndReceiveState(addr, join) + remote, userState, err := m.sendAndReceiveState(a, join) if err != nil { return err } @@ -638,7 +682,7 @@ func (m *Memberlist) verifyProtocol(remote []pushNodeState) error { for _, rn := range remote { // If the node isn't alive, then skip it - if rn.State != stateAlive { + if rn.State != StateAlive { continue } @@ -667,7 +711,7 @@ func (m *Memberlist) verifyProtocol(remote []pushNodeState) error { for _, n := range m.nodes { // Ignore non-alive nodes - if n.State != stateAlive { + if n.State != StateAlive { continue } @@ -926,6 +970,11 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) { // store this node in our node map. var updatesNode bool if !ok { + errCon := m.config.IPAllowed(a.Addr) + if errCon != nil { + m.logger.Printf("[WARN] memberlist: Rejected node %s (%v): %s", a.Node, net.IP(a.Addr), errCon) + return + } state = &nodeState{ Node: Node{ Name: a.Node, @@ -933,7 +982,7 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) { Port: a.Port, Meta: a.Meta, }, - State: stateDead, + State: StateDead, } if len(a.Vsn) > 5 { state.PMin = a.Vsn[0] @@ -963,12 +1012,17 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) { } else { // Check if this address is different than the existing node unless the old node is dead. if !bytes.Equal([]byte(state.Addr), a.Addr) || state.Port != a.Port { + errCon := m.config.IPAllowed(a.Addr) + if errCon != nil { + m.logger.Printf("[WARN] memberlist: Rejected IP update from %v to %v for node %s: %s", a.Node, state.Addr, net.IP(a.Addr), errCon) + return + } // If DeadNodeReclaimTime is configured, check if enough time has elapsed since the node died. canReclaim := (m.config.DeadNodeReclaimTime > 0 && time.Since(state.StateChange) > m.config.DeadNodeReclaimTime) // Allow the address to be updated if a dead node is being replaced. - if state.State == stateLeft || (state.State == stateDead && canReclaim) { + if state.State == StateLeft || (state.State == StateDead && canReclaim) { m.logger.Printf("[INFO] memberlist: Updating address for left or failed node %s from %v:%d to %v:%d", state.Name, state.Addr, state.Port, net.IP(a.Addr), a.Port) updatesNode = true @@ -1053,8 +1107,8 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) { state.Meta = a.Meta state.Addr = a.Addr state.Port = a.Port - if state.State != stateAlive { - state.State = stateAlive + if state.State != StateAlive { + state.State = StateAlive state.StateChange = time.Now() } } @@ -1064,7 +1118,7 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) { // Notify the delegate of any relevant updates if m.config.Events != nil { - if oldState == stateDead || oldState == stateLeft { + if oldState == StateDead || oldState == StateLeft { // if Dead/Left -> Alive, notify of join m.config.Events.NotifyJoin(&state.Node) @@ -1104,7 +1158,7 @@ func (m *Memberlist) suspectNode(s *suspect) { } // Ignore non-alive nodes - if state.State != stateAlive { + if state.State != StateAlive { return } @@ -1122,7 +1176,7 @@ func (m *Memberlist) suspectNode(s *suspect) { // Update the state state.Incarnation = s.Incarnation - state.State = stateSuspect + state.State = StateSuspect changeTime := time.Now() state.StateChange = changeTime @@ -1146,7 +1200,7 @@ func (m *Memberlist) suspectNode(s *suspect) { fn := func(numConfirmations int) { m.nodeLock.Lock() state, ok := m.nodeMap[s.Node] - timeout := ok && state.State == stateSuspect && state.StateChange == changeTime + timeout := ok && state.State == StateSuspect && state.StateChange == changeTime m.nodeLock.Unlock() if timeout { @@ -1212,9 +1266,9 @@ func (m *Memberlist) deadNode(d *dead) { // If the dead message was send by the node itself, mark it is left // instead of dead. if d.Node == d.From { - state.State = stateLeft + state.State = StateLeft } else { - state.State = stateDead + state.State = StateDead } state.StateChange = time.Now() @@ -1229,7 +1283,7 @@ func (m *Memberlist) deadNode(d *dead) { func (m *Memberlist) mergeState(remote []pushNodeState) { for _, r := range remote { switch r.State { - case stateAlive: + case StateAlive: a := alive{ Incarnation: r.Incarnation, Node: r.Name, @@ -1240,14 +1294,14 @@ func (m *Memberlist) mergeState(remote []pushNodeState) { } m.aliveNode(&a, nil, false) - case stateLeft: + case StateLeft: d := dead{Incarnation: r.Incarnation, Node: r.Name, From: r.Name} m.deadNode(&d) - case stateDead: + case StateDead: // If the remote node believes a node is dead, we prefer to // suspect that node instead of declaring it dead instantly fallthrough - case stateSuspect: + case StateSuspect: s := suspect{Incarnation: r.Incarnation, Node: r.Name, From: m.config.Name} m.suspectNode(&s) } diff --git a/vendor/github.com/hashicorp/memberlist/transport.go b/vendor/github.com/hashicorp/memberlist/transport.go index 6ce55ea47..1cd590c6a 100644 --- a/vendor/github.com/hashicorp/memberlist/transport.go +++ b/vendor/github.com/hashicorp/memberlist/transport.go @@ -1,6 +1,7 @@ package memberlist import ( + "fmt" "net" "time" ) @@ -63,3 +64,64 @@ type Transport interface { // transport a chance to clean up any listeners. Shutdown() error } + +type Address struct { + // Addr is a network address as a string, similar to Dial. This usually is + // in the form of "host:port". This is required. + Addr string + + // Name is the name of the node being addressed. This is optional but + // transports may require it. + Name string +} + +func (a *Address) String() string { + if a.Name != "" { + return fmt.Sprintf("%s (%s)", a.Name, a.Addr) + } + return a.Addr +} + +type IngestionAwareTransport interface { + Transport + // IngestPacket pulls a single packet off the conn, and only closes it if shouldClose is true. + IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error + // IngestStream hands off the conn to the transport and doesn't close it. + IngestStream(conn net.Conn) error +} + +type NodeAwareTransport interface { + IngestionAwareTransport + WriteToAddress(b []byte, addr Address) (time.Time, error) + DialAddressTimeout(addr Address, timeout time.Duration) (net.Conn, error) +} + +type shimNodeAwareTransport struct { + Transport +} + +var _ NodeAwareTransport = (*shimNodeAwareTransport)(nil) + +func (t *shimNodeAwareTransport) IngestPacket(conn net.Conn, addr net.Addr, now time.Time, shouldClose bool) error { + iat, ok := t.Transport.(IngestionAwareTransport) + if !ok { + panic("shimNodeAwareTransport does not support IngestPacket") + } + return iat.IngestPacket(conn, addr, now, shouldClose) +} + +func (t *shimNodeAwareTransport) IngestStream(conn net.Conn) error { + iat, ok := t.Transport.(IngestionAwareTransport) + if !ok { + panic("shimNodeAwareTransport does not support IngestStream") + } + return iat.IngestStream(conn) +} + +func (t *shimNodeAwareTransport) WriteToAddress(b []byte, addr Address) (time.Time, error) { + return t.WriteTo(b, addr.Addr) +} + +func (t *shimNodeAwareTransport) DialAddressTimeout(addr Address, timeout time.Duration) (net.Conn, error) { + return t.DialTimeout(addr.Addr, timeout) +} diff --git a/vendor/github.com/hashicorp/memberlist/util.go b/vendor/github.com/hashicorp/memberlist/util.go index 1e582a8a1..22bf6b440 100644 --- a/vendor/github.com/hashicorp/memberlist/util.go +++ b/vendor/github.com/hashicorp/memberlist/util.go @@ -102,7 +102,7 @@ func moveDeadNodes(nodes []*nodeState, gossipToTheDeadTime time.Duration) int { numDead := 0 n := len(nodes) for i := 0; i < n-numDead; i++ { - if nodes[i].State != stateDead { + if nodes[i].State != StateDead { continue } diff --git a/vendor/github.com/hashicorp/nomad/api/scaling.go b/vendor/github.com/hashicorp/nomad/api/scaling.go index 9f5f03de5..669fec8e0 100644 --- a/vendor/github.com/hashicorp/nomad/api/scaling.go +++ b/vendor/github.com/hashicorp/nomad/api/scaling.go @@ -76,6 +76,7 @@ type ScalingPolicyListStub struct { // JobScaleStatusResponse is used to return information about job scaling status type JobScaleStatusResponse struct { JobID string + Namespace string JobCreateIndex uint64 JobModifyIndex uint64 JobStopped bool diff --git a/vendor/github.com/hashicorp/serf/serf/config.go b/vendor/github.com/hashicorp/serf/serf/config.go index 0de4247c5..2875e1d60 100644 --- a/vendor/github.com/hashicorp/serf/serf/config.go +++ b/vendor/github.com/hashicorp/serf/serf/config.go @@ -246,6 +246,13 @@ type Config struct { // UserEventSizeLimit is maximum byte size limit of user event `name` + `payload` in bytes. // It's optimal to be relatively small, since it's going to be gossiped through the cluster. UserEventSizeLimit int + + // messageDropper is a callback used for selectively ignoring inbound + // gossip messages. This should only be used in unit tests needing careful + // control over sequencing of gossip arrival + // + // WARNING: this should ONLY be used in tests + messageDropper func(typ messageType) bool } // Init allocates the subdata structures @@ -253,6 +260,11 @@ func (c *Config) Init() { if c.Tags == nil { c.Tags = make(map[string]string) } + if c.messageDropper == nil { + c.messageDropper = func(typ messageType) bool { + return false + } + } } // DefaultConfig returns a Config struct that contains reasonable defaults diff --git a/vendor/github.com/hashicorp/serf/serf/delegate.go b/vendor/github.com/hashicorp/serf/serf/delegate.go index 567c7fe4a..a6d23d116 100644 --- a/vendor/github.com/hashicorp/serf/serf/delegate.go +++ b/vendor/github.com/hashicorp/serf/serf/delegate.go @@ -35,6 +35,11 @@ func (d *delegate) NotifyMsg(buf []byte) { rebroadcast := false rebroadcastQueue := d.serf.broadcasts t := messageType(buf[0]) + + if d.serf.config.messageDropper(t) { + return + } + switch t { case messageLeaveType: var leave messageLeave @@ -101,8 +106,14 @@ func (d *delegate) NotifyMsg(buf []byte) { // The remaining contents are the message itself, so forward that raw := make([]byte, reader.Len()) reader.Read(raw) + + addr := memberlist.Address{ + Addr: header.DestAddr.String(), + Name: header.DestName, + } + d.serf.logger.Printf("[DEBUG] serf: Relaying response to addr: %s", header.DestAddr.String()) - if err := d.serf.memberlist.SendTo(&header.DestAddr, raw); err != nil { + if err := d.serf.memberlist.SendToAddress(addr, raw); err != nil { d.serf.logger.Printf("[ERR] serf: Error forwarding message to %s: %s", header.DestAddr.String(), err) break } @@ -207,6 +218,10 @@ func (d *delegate) MergeRemoteState(buf []byte, isJoin bool) { return } + if d.serf.config.messageDropper(messagePushPullType) { + return + } + // Attempt a decode pp := messagePushPull{} if err := decodeMessage(buf[1:], &pp); err != nil { diff --git a/vendor/github.com/hashicorp/serf/serf/event.go b/vendor/github.com/hashicorp/serf/serf/event.go index 859a09e56..c83b00959 100644 --- a/vendor/github.com/hashicorp/serf/serf/event.go +++ b/vendor/github.com/hashicorp/serf/serf/event.go @@ -5,6 +5,8 @@ import ( "net" "sync" "time" + + "github.com/hashicorp/memberlist" ) // EventType are all the types of events that may occur and be sent @@ -105,6 +107,7 @@ type Query struct { id uint32 // ID is not exported, since it may change addr []byte // Address to respond to port uint16 // Port to respond to + sourceNode string // Node name to respond to deadline time.Time // Must respond by this deadline relayFactor uint8 // Number of duplicate responses to relay back to sender respLock sync.Mutex @@ -161,13 +164,18 @@ func (q *Query) respondWithMessageAndResponse(raw []byte, resp messageQueryRespo } // Send the response directly to the originator - addr := net.UDPAddr{IP: q.addr, Port: int(q.port)} - if err := q.serf.memberlist.SendTo(&addr, raw); err != nil { + udpAddr := net.UDPAddr{IP: q.addr, Port: int(q.port)} + + addr := memberlist.Address{ + Addr: udpAddr.String(), + Name: q.sourceNode, + } + if err := q.serf.memberlist.SendToAddress(addr, raw); err != nil { return err } // Relay the response through up to relayFactor other nodes - if err := q.serf.relayResponse(q.relayFactor, addr, &resp); err != nil { + if err := q.serf.relayResponse(q.relayFactor, udpAddr, q.sourceNode, &resp); err != nil { return err } diff --git a/vendor/github.com/hashicorp/serf/serf/merge_delegate.go b/vendor/github.com/hashicorp/serf/serf/merge_delegate.go index 7fdc73288..36eb52f7d 100644 --- a/vendor/github.com/hashicorp/serf/serf/merge_delegate.go +++ b/vendor/github.com/hashicorp/serf/serf/merge_delegate.go @@ -28,12 +28,17 @@ func (m *mergeDelegate) NotifyAlive(peer *memberlist.Node) error { } func (m *mergeDelegate) nodeToMember(n *memberlist.Node) *Member { + status := StatusNone + if n.State == memberlist.StateLeft { + status = StatusLeft + } + return &Member{ Name: n.Name, Addr: net.IP(n.Addr), Port: n.Port, Tags: m.serf.decodeTags(n.Meta), - Status: StatusNone, + Status: status, ProtocolMin: n.PMin, ProtocolMax: n.PMax, ProtocolCur: n.PCur, diff --git a/vendor/github.com/hashicorp/serf/serf/messages.go b/vendor/github.com/hashicorp/serf/serf/messages.go index 138817c50..7af15ff43 100644 --- a/vendor/github.com/hashicorp/serf/serf/messages.go +++ b/vendor/github.com/hashicorp/serf/serf/messages.go @@ -83,6 +83,7 @@ type messageQuery struct { ID uint32 // Query ID, randomly generated Addr []byte // Source address, used for a direct reply Port uint16 // Source port, used for a direct reply + SourceNode string // Source name, used for a direct reply Filters [][]byte // Potential query filters Flags uint32 // Used to provide various flags RelayFactor uint8 // Used to set the number of duplicate relayed responses @@ -144,22 +145,33 @@ func encodeMessage(t messageType, msg interface{}) ([]byte, error) { // relayHeader is used to store the end destination of a relayed message type relayHeader struct { DestAddr net.UDPAddr + DestName string } // encodeRelayMessage wraps a message in the messageRelayType, adding the length and // address of the end recipient to the front of the message -func encodeRelayMessage(t messageType, addr net.UDPAddr, msg interface{}) ([]byte, error) { +func encodeRelayMessage( + t messageType, + addr net.UDPAddr, + nodeName string, + msg interface{}, +) ([]byte, error) { buf := bytes.NewBuffer(nil) handle := codec.MsgpackHandle{} encoder := codec.NewEncoder(buf, &handle) buf.WriteByte(uint8(messageRelayType)) - if err := encoder.Encode(relayHeader{DestAddr: addr}); err != nil { + + err := encoder.Encode(relayHeader{ + DestAddr: addr, + DestName: nodeName, + }) + if err != nil { return nil, err } buf.WriteByte(uint8(t)) - err := encoder.Encode(msg) + err = encoder.Encode(msg) return buf.Bytes(), err } diff --git a/vendor/github.com/hashicorp/serf/serf/query.go b/vendor/github.com/hashicorp/serf/serf/query.go index 0bdbb3553..5054000ef 100644 --- a/vendor/github.com/hashicorp/serf/serf/query.go +++ b/vendor/github.com/hashicorp/serf/serf/query.go @@ -9,6 +9,8 @@ import ( "regexp" "sync" "time" + + "github.com/hashicorp/memberlist" ) // QueryParam is provided to Query() to configure the parameters of the @@ -243,7 +245,12 @@ func (s *Serf) shouldProcessQuery(filters [][]byte) bool { // relayResponse will relay a copy of the given response to up to relayFactor // other members. -func (s *Serf) relayResponse(relayFactor uint8, addr net.UDPAddr, resp *messageQueryResponse) error { +func (s *Serf) relayResponse( + relayFactor uint8, + addr net.UDPAddr, + nodeName string, + resp *messageQueryResponse, +) error { if relayFactor == 0 { return nil } @@ -257,7 +264,7 @@ func (s *Serf) relayResponse(relayFactor uint8, addr net.UDPAddr, resp *messageQ } // Prep the relay message, which is a wrapped version of the original. - raw, err := encodeRelayMessage(messageQueryResponseType, addr, &resp) + raw, err := encodeRelayMessage(messageQueryResponseType, addr, nodeName, &resp) if err != nil { return fmt.Errorf("failed to format relayed response: %v", err) } @@ -271,8 +278,12 @@ func (s *Serf) relayResponse(relayFactor uint8, addr net.UDPAddr, resp *messageQ return m.Status != StatusAlive || m.ProtocolMax < 5 || m.Name == localName }) for _, m := range relayMembers { - relayAddr := net.UDPAddr{IP: m.Addr, Port: int(m.Port)} - if err := s.memberlist.SendTo(&relayAddr, raw); err != nil { + udpAddr := net.UDPAddr{IP: m.Addr, Port: int(m.Port)} + relayAddr := memberlist.Address{ + Addr: udpAddr.String(), + Name: m.Name, + } + if err := s.memberlist.SendToAddress(relayAddr, raw); err != nil { return fmt.Errorf("failed to send relay response: %v", err) } } diff --git a/vendor/github.com/hashicorp/serf/serf/serf.go b/vendor/github.com/hashicorp/serf/serf/serf.go index 9fe4cc3a7..1c1dda1dd 100644 --- a/vendor/github.com/hashicorp/serf/serf/serf.go +++ b/vendor/github.com/hashicorp/serf/serf/serf.go @@ -541,6 +541,7 @@ func (s *Serf) Query(name string, payload []byte, params *QueryParam) (*QueryRes ID: uint32(rand.Int31()), Addr: local.Addr, Port: local.Port, + SourceNode: local.Name, Filters: filters, Flags: flags, RelayFactor: params.RelayFactor, @@ -906,6 +907,10 @@ func (s *Serf) handleNodeJoin(n *memberlist.Node) { s.memberLock.Lock() defer s.memberLock.Unlock() + if s.config.messageDropper(messageJoinType) { + return + } + var oldStatus MemberStatus member, ok := s.members[n.Name] if !ok { @@ -1097,11 +1102,14 @@ func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool { return false } + // Always set the lamport time so that if we retransmit below it won't echo + // around forever! + member.statusLTime = leaveMsg.LTime + // State transition depends on current state switch member.Status { case StatusAlive: member.Status = StatusLeaving - member.statusLTime = leaveMsg.LTime if leaveMsg.Prune { s.handlePrune(member) @@ -1109,7 +1117,6 @@ func (s *Serf) handleNodeLeaveIntent(leaveMsg *messageLeave) bool { return true case StatusFailed: member.Status = StatusLeft - member.statusLTime = leaveMsg.LTime // Remove from the failed list and add to the left list. We add // to the left list so that when we do a sync, other nodes will @@ -1326,11 +1333,15 @@ func (s *Serf) handleQuery(query *messageQuery) bool { if err != nil { s.logger.Printf("[ERR] serf: failed to format ack: %v", err) } else { - addr := net.UDPAddr{IP: query.Addr, Port: int(query.Port)} - if err := s.memberlist.SendTo(&addr, raw); err != nil { + udpAddr := net.UDPAddr{IP: query.Addr, Port: int(query.Port)} + addr := memberlist.Address{ + Addr: udpAddr.String(), + Name: query.SourceNode, + } + if err := s.memberlist.SendToAddress(addr, raw); err != nil { s.logger.Printf("[ERR] serf: failed to send ack: %v", err) } - if err := s.relayResponse(query.RelayFactor, addr, &ack); err != nil { + if err := s.relayResponse(query.RelayFactor, udpAddr, query.SourceNode, &ack); err != nil { s.logger.Printf("[ERR] serf: failed to relay ack: %v", err) } } @@ -1345,6 +1356,7 @@ func (s *Serf) handleQuery(query *messageQuery) bool { id: query.ID, addr: query.Addr, port: query.Port, + sourceNode: query.SourceNode, deadline: time.Now().Add(query.Timeout), relayFactor: query.RelayFactor, } @@ -1603,8 +1615,13 @@ func (s *Serf) reconnect() { addr := net.UDPAddr{IP: mem.Addr, Port: int(mem.Port)} s.logger.Printf("[INFO] serf: attempting reconnect to %v %s", mem.Name, addr.String()) + joinAddr := addr.String() + if mem.Name != "" { + joinAddr = mem.Name + "/" + addr.String() + } + // Attempt to join at the memberlist level - s.memberlist.Join([]string{addr.String()}) + s.memberlist.Join([]string{joinAddr}) } // getQueueMax will get the maximum queue depth, which might be dynamic depending @@ -1709,8 +1726,13 @@ func (s *Serf) handleRejoin(previous []*PreviousNode) { continue } + joinAddr := prev.Addr + if prev.Name != "" { + joinAddr = prev.Name + "/" + prev.Addr + } + s.logger.Printf("[INFO] serf: Attempting re-join to previously known node: %s", prev) - _, err := s.memberlist.Join([]string{prev.Addr}) + _, err := s.memberlist.Join([]string{joinAddr}) if err == nil { s.logger.Printf("[INFO] serf: Re-joined to previously known node: %s", prev) return diff --git a/vendor/github.com/mitchellh/cli/.travis.yml b/vendor/github.com/mitchellh/cli/.travis.yml index b8599b3ac..5c01b3a0e 100644 --- a/vendor/github.com/mitchellh/cli/.travis.yml +++ b/vendor/github.com/mitchellh/cli/.travis.yml @@ -2,10 +2,14 @@ sudo: false language: go +env: + - GO111MODULE=on + go: - - "1.8" - - "1.9" - - "1.10" + - "1.11" + - "1.12" + - "1.13" + - "1.14" branches: only: diff --git a/vendor/github.com/mitchellh/cli/Makefile b/vendor/github.com/mitchellh/cli/Makefile index 4874b0082..89c0a1209 100644 --- a/vendor/github.com/mitchellh/cli/Makefile +++ b/vendor/github.com/mitchellh/cli/Makefile @@ -12,9 +12,6 @@ testrace: # updatedeps installs all the dependencies to run and build updatedeps: - go list ./... \ - | xargs go list -f '{{ join .Deps "\n" }}{{ printf "\n" }}{{ join .TestImports "\n" }}' \ - | grep -v github.com/mitchellh/cli \ - | xargs go get -f -u -v + go mod download .PHONY: test testrace updatedeps diff --git a/vendor/github.com/mitchellh/cli/cli.go b/vendor/github.com/mitchellh/cli/cli.go index c2dbe55aa..0a6b6cba9 100644 --- a/vendor/github.com/mitchellh/cli/cli.go +++ b/vendor/github.com/mitchellh/cli/cli.go @@ -109,18 +109,23 @@ type CLI struct { AutocompleteGlobalFlags complete.Flags autocompleteInstaller autocompleteInstaller // For tests - // HelpFunc and HelpWriter are used to output help information, if - // requested. - // // HelpFunc is the function called to generate the generic help // text that is shown if help must be shown for the CLI that doesn't // pertain to a specific command. - // - // HelpWriter is the Writer where the help text is outputted to. If - // not specified, it will default to Stderr. - HelpFunc HelpFunc + HelpFunc HelpFunc + + // HelpWriter is used to print help text and version when requested. + // Defaults to os.Stderr for backwards compatibility. + // It is recommended that you set HelpWriter to os.Stdout, and + // ErrorWriter to os.Stderr. HelpWriter io.Writer + // ErrorWriter used to output errors when a command can not be run. + // Defaults to the value of HelpWriter for backwards compatibility. + // It is recommended that you set HelpWriter to os.Stdout, and + // ErrorWriter to os.Stderr. + ErrorWriter io.Writer + //--------------------------------------------------------------- // Internal fields set automatically @@ -228,7 +233,7 @@ func (c *CLI) Run() (int, error) { // implementation. If the command is invalid or blank, it is an error. raw, ok := c.commandTree.Get(c.Subcommand()) if !ok { - c.HelpWriter.Write([]byte(c.HelpFunc(c.helpCommands(c.subcommandParent())) + "\n")) + c.ErrorWriter.Write([]byte(c.HelpFunc(c.helpCommands(c.subcommandParent())) + "\n")) return 127, nil } @@ -239,23 +244,23 @@ func (c *CLI) Run() (int, error) { // If we've been instructed to just print the help, then print it if c.IsHelp() { - c.commandHelp(command) + c.commandHelp(c.HelpWriter, command) return 0, nil } // If there is an invalid flag, then error if len(c.topFlags) > 0 { - c.HelpWriter.Write([]byte( + c.ErrorWriter.Write([]byte( "Invalid flags before the subcommand. If these flags are for\n" + "the subcommand, please put them after the subcommand.\n\n")) - c.commandHelp(command) + c.commandHelp(c.ErrorWriter, command) return 1, nil } code := command.Run(c.SubcommandArgs()) if code == RunResultHelp { // Requesting help - c.commandHelp(command) + c.commandHelp(c.ErrorWriter, command) return 1, nil } @@ -310,6 +315,9 @@ func (c *CLI) init() { if c.HelpWriter == nil { c.HelpWriter = os.Stderr } + if c.ErrorWriter == nil { + c.ErrorWriter = c.HelpWriter + } // Build our hidden commands if len(c.HiddenCommands) > 0 { @@ -404,8 +412,8 @@ func (c *CLI) initAutocomplete() { cmd.Flags = map[string]complete.Predictor{ "-" + c.AutocompleteInstall: complete.PredictNothing, "-" + c.AutocompleteUninstall: complete.PredictNothing, - "-help": complete.PredictNothing, - "-version": complete.PredictNothing, + "-help": complete.PredictNothing, + "-version": complete.PredictNothing, } } cmd.GlobalFlags = c.AutocompleteGlobalFlags @@ -483,7 +491,7 @@ func (c *CLI) initAutocompleteSub(prefix string) complete.Command { return cmd } -func (c *CLI) commandHelp(command Command) { +func (c *CLI) commandHelp(out io.Writer, command Command) { // Get the template to use tpl := strings.TrimSpace(defaultHelpTemplate) if t, ok := command.(CommandHelpTemplate); ok { @@ -533,12 +541,12 @@ func (c *CLI) commandHelp(command Command) { // Get the command raw, ok := subcommands[k] if !ok { - c.HelpWriter.Write([]byte(fmt.Sprintf( + c.ErrorWriter.Write([]byte(fmt.Sprintf( "Error getting subcommand %q", k))) } sub, err := raw() if err != nil { - c.HelpWriter.Write([]byte(fmt.Sprintf( + c.ErrorWriter.Write([]byte(fmt.Sprintf( "Error instantiating %q: %s", k, err))) } @@ -559,13 +567,13 @@ func (c *CLI) commandHelp(command Command) { data["Subcommands"] = subcommandsTpl // Write - err = t.Execute(c.HelpWriter, data) + err = t.Execute(out, data) if err == nil { return } // An error, just output... - c.HelpWriter.Write([]byte(fmt.Sprintf( + c.ErrorWriter.Write([]byte(fmt.Sprintf( "Internal error rendering help: %s", err))) } diff --git a/vendor/github.com/mitchellh/cli/go.mod b/vendor/github.com/mitchellh/cli/go.mod index 675325ffa..bd6c53d35 100644 --- a/vendor/github.com/mitchellh/cli/go.mod +++ b/vendor/github.com/mitchellh/cli/go.mod @@ -1,5 +1,7 @@ module github.com/mitchellh/cli +go 1.11 + require ( github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 github.com/bgentry/speakeasy v0.1.0 diff --git a/vendor/github.com/mitchellh/cli/ui_mock.go b/vendor/github.com/mitchellh/cli/ui_mock.go index 0bfe0a191..935f28a4a 100644 --- a/vendor/github.com/mitchellh/cli/ui_mock.go +++ b/vendor/github.com/mitchellh/cli/ui_mock.go @@ -1,9 +1,11 @@ package cli import ( + "bufio" "bytes" "fmt" "io" + "strings" "sync" ) @@ -35,9 +37,12 @@ func (u *MockUi) Ask(query string) (string, error) { var result string fmt.Fprint(u.OutputWriter, query) - if _, err := fmt.Fscanln(u.InputReader, &result); err != nil { + r := bufio.NewReader(u.InputReader) + line, err := r.ReadString('\n') + if err != nil { return "", err } + result = strings.TrimRight(line, "\r\n") return result, nil } diff --git a/vendor/github.com/posener/complete/.travis.yml b/vendor/github.com/posener/complete/.travis.yml index 2fae94541..6ba8d865b 100644 --- a/vendor/github.com/posener/complete/.travis.yml +++ b/vendor/github.com/posener/complete/.travis.yml @@ -1,16 +1,16 @@ language: go -sudo: false go: - - 1.11 + - tip + - 1.12.x + - 1.11.x - 1.10.x - - 1.9 - - 1.8 - -before_install: - - go get -u -t ./... script: - - GO111MODULE=on ./test.sh + - go test -race -coverprofile=coverage.txt -covermode=atomic ./... after_success: - bash <(curl -s https://codecov.io/bash) + +matrix: + allow_failures: + - go: tip \ No newline at end of file diff --git a/vendor/github.com/posener/complete/args.go b/vendor/github.com/posener/complete/args.go index 17ab2c6d6..3340285e1 100644 --- a/vendor/github.com/posener/complete/args.go +++ b/vendor/github.com/posener/complete/args.go @@ -28,6 +28,8 @@ type Args struct { // Directory gives the directory of the current written // last argument if it represents a file name being written. // in case that it is not, we fall back to the current directory. +// +// Deprecated. func (a Args) Directory() string { if info, err := os.Stat(a.Last); err == nil && info.IsDir() { return fixPathForm(a.Last, a.Last) @@ -83,16 +85,17 @@ func splitLastEqual(line []string) []string { return append(line[:len(line)-1], parts...) } +// from returns a copy of Args of all arguments after the i'th argument. func (a Args) from(i int) Args { - if i > len(a.All) { - i = len(a.All) + if i >= len(a.All) { + i = len(a.All) - 1 } - a.All = a.All[i:] + a.All = a.All[i+1:] - if i > len(a.Completed) { - i = len(a.Completed) + if i >= len(a.Completed) { + i = len(a.Completed) - 1 } - a.Completed = a.Completed[i:] + a.Completed = a.Completed[i+1:] return a } diff --git a/vendor/github.com/posener/complete/cmd/install/bash.go b/vendor/github.com/posener/complete/cmd/install/bash.go index a287f9986..17c64de13 100644 --- a/vendor/github.com/posener/complete/cmd/install/bash.go +++ b/vendor/github.com/posener/complete/cmd/install/bash.go @@ -10,20 +10,25 @@ type bash struct { rc string } -func (b bash) Install(cmd, bin string) error { +func (b bash) IsInstalled(cmd, bin string) bool { completeCmd := b.cmd(cmd, bin) - if lineInFile(b.rc, completeCmd) { + return lineInFile(b.rc, completeCmd) +} + +func (b bash) Install(cmd, bin string) error { + if b.IsInstalled(cmd, bin) { return fmt.Errorf("already installed in %s", b.rc) } + completeCmd := b.cmd(cmd, bin) return appendToFile(b.rc, completeCmd) } func (b bash) Uninstall(cmd, bin string) error { - completeCmd := b.cmd(cmd, bin) - if !lineInFile(b.rc, completeCmd) { + if !b.IsInstalled(cmd, bin) { return fmt.Errorf("does not installed in %s", b.rc) } + completeCmd := b.cmd(cmd, bin) return removeFromFile(b.rc, completeCmd) } diff --git a/vendor/github.com/posener/complete/cmd/install/fish.go b/vendor/github.com/posener/complete/cmd/install/fish.go index 6467196bc..2b64bfc83 100644 --- a/vendor/github.com/posener/complete/cmd/install/fish.go +++ b/vendor/github.com/posener/complete/cmd/install/fish.go @@ -14,39 +14,52 @@ type fish struct { configDir string } +func (f fish) IsInstalled(cmd, bin string) bool { + completionFile := f.getCompletionFilePath(cmd) + if _, err := os.Stat(completionFile); err == nil { + return true + } + return false +} + func (f fish) Install(cmd, bin string) error { - completionFile := filepath.Join(f.configDir, "completions", fmt.Sprintf("%s.fish", cmd)) + if f.IsInstalled(cmd, bin) { + return fmt.Errorf("already installed at %s", f.getCompletionFilePath(cmd)) + } + + completionFile := f.getCompletionFilePath(cmd) completeCmd, err := f.cmd(cmd, bin) if err != nil { return err } - if _, err := os.Stat(completionFile); err == nil { - return fmt.Errorf("already installed at %s", completionFile) - } return createFile(completionFile, completeCmd) } func (f fish) Uninstall(cmd, bin string) error { - completionFile := filepath.Join(f.configDir, "completions", fmt.Sprintf("%s.fish", cmd)) - if _, err := os.Stat(completionFile); err != nil { + if !f.IsInstalled(cmd, bin) { return fmt.Errorf("does not installed in %s", f.configDir) } + completionFile := f.getCompletionFilePath(cmd) return os.Remove(completionFile) } +func (f fish) getCompletionFilePath(cmd string) string { + return filepath.Join(f.configDir, "completions", fmt.Sprintf("%s.fish", cmd)) +} + func (f fish) cmd(cmd, bin string) (string, error) { var buf bytes.Buffer params := struct{ Cmd, Bin string }{cmd, bin} tmpl := template.Must(template.New("cmd").Parse(` function __complete_{{.Cmd}} - set -lx COMP_LINE (string join ' ' (commandline -o)) - test (commandline -ct) = "" + set -lx COMP_LINE (commandline -cp) + test -z (commandline -ct) and set COMP_LINE "$COMP_LINE " {{.Bin}} end -complete -c {{.Cmd}} -a "(__complete_{{.Cmd}})" +complete -f -c {{.Cmd}} -a "(__complete_{{.Cmd}})" `)) err := tmpl.Execute(&buf, params) if err != nil { diff --git a/vendor/github.com/posener/complete/cmd/install/install.go b/vendor/github.com/posener/complete/cmd/install/install.go index dfa1963b8..884c23f5b 100644 --- a/vendor/github.com/posener/complete/cmd/install/install.go +++ b/vendor/github.com/posener/complete/cmd/install/install.go @@ -5,11 +5,13 @@ import ( "os" "os/user" "path/filepath" + "runtime" "github.com/hashicorp/go-multierror" ) type installer interface { + IsInstalled(cmd, bin string) bool Install(cmd, bin string) error Uninstall(cmd, bin string) error } @@ -36,6 +38,24 @@ func Install(cmd string) error { return err } +// IsInstalled returns true if the completion +// for the given cmd is installed. +func IsInstalled(cmd string) bool { + bin, err := getBinaryPath() + if err != nil { + return false + } + + for _, i := range installers() { + installed := i.IsInstalled(cmd, bin) + if installed { + return true + } + } + + return false +} + // Uninstall complete command given: // cmd: is the command name func Uninstall(cmd string) error { @@ -59,7 +79,16 @@ func Uninstall(cmd string) error { } func installers() (i []installer) { - for _, rc := range [...]string{".bashrc", ".bash_profile", ".bash_login", ".profile"} { + // The list of bash config files candidates where it is + // possible to install the completion command. + var bashConfFiles []string + switch runtime.GOOS { + case "darwin": + bashConfFiles = []string{".bash_profile"} + default: + bashConfFiles = []string{".bashrc", ".bash_profile", ".bash_login", ".profile"} + } + for _, rc := range bashConfFiles { if f := rcFile(rc); f != "" { i = append(i, bash{f}) break diff --git a/vendor/github.com/posener/complete/cmd/install/zsh.go b/vendor/github.com/posener/complete/cmd/install/zsh.go index a625f53cf..29950ab17 100644 --- a/vendor/github.com/posener/complete/cmd/install/zsh.go +++ b/vendor/github.com/posener/complete/cmd/install/zsh.go @@ -11,12 +11,17 @@ type zsh struct { rc string } -func (z zsh) Install(cmd, bin string) error { +func (z zsh) IsInstalled(cmd, bin string) bool { completeCmd := z.cmd(cmd, bin) - if lineInFile(z.rc, completeCmd) { + return lineInFile(z.rc, completeCmd) +} + +func (z zsh) Install(cmd, bin string) error { + if z.IsInstalled(cmd, bin) { return fmt.Errorf("already installed in %s", z.rc) } + completeCmd := z.cmd(cmd, bin) bashCompInit := "autoload -U +X bashcompinit && bashcompinit" if !lineInFile(z.rc, bashCompInit) { completeCmd = bashCompInit + "\n" + completeCmd @@ -26,11 +31,11 @@ func (z zsh) Install(cmd, bin string) error { } func (z zsh) Uninstall(cmd, bin string) error { - completeCmd := z.cmd(cmd, bin) - if !lineInFile(z.rc, completeCmd) { + if !z.IsInstalled(cmd, bin) { return fmt.Errorf("does not installed in %s", z.rc) } + completeCmd := z.cmd(cmd, bin) return removeFromFile(z.rc, completeCmd) } diff --git a/vendor/github.com/posener/complete/complete.go b/vendor/github.com/posener/complete/complete.go index 725c4debc..423cbec6c 100644 --- a/vendor/github.com/posener/complete/complete.go +++ b/vendor/github.com/posener/complete/complete.go @@ -1,8 +1,3 @@ -// Package complete provides a tool for bash writing bash completion in go. -// -// Writing bash completion scripts is a hard work. This package provides an easy way -// to create bash completion scripts for any command, and also an easy way to install/uninstall -// the completion of the command. package complete import ( @@ -11,9 +6,9 @@ import ( "io" "os" "strconv" + "strings" "github.com/posener/complete/cmd" - "github.com/posener/complete/match" ) const ( @@ -77,7 +72,7 @@ func (c *Complete) Complete() bool { // filter only options that match the last argument matches := []string{} for _, option := range options { - if match.Prefix(option, a.Last) { + if strings.HasPrefix(option, a.Last) { matches = append(matches, option) } } diff --git a/vendor/github.com/posener/complete/doc.go b/vendor/github.com/posener/complete/doc.go new file mode 100644 index 000000000..0ae09a1b7 --- /dev/null +++ b/vendor/github.com/posener/complete/doc.go @@ -0,0 +1,110 @@ +/* +Package complete provides a tool for bash writing bash completion in go, and bash completion for the go command line. + +Writing bash completion scripts is a hard work. This package provides an easy way +to create bash completion scripts for any command, and also an easy way to install/uninstall +the completion of the command. + +Go Command Bash Completion + +In ./cmd/gocomplete there is an example for bash completion for the `go` command line. + +This is an example that uses the `complete` package on the `go` command - the `complete` package +can also be used to implement any completions, see #usage. + +Install + +1. Type in your shell: + + go get -u github.com/posener/complete/gocomplete + gocomplete -install + +2. Restart your shell + +Uninstall by `gocomplete -uninstall` + +Features + +- Complete `go` command, including sub commands and all flags. +- Complete packages names or `.go` files when necessary. +- Complete test names after `-run` flag. + +Complete package + +Supported shells: + +- [x] bash +- [x] zsh +- [x] fish + +Usage + +Assuming you have program called `run` and you want to have bash completion +for it, meaning, if you type `run` then space, then press the `Tab` key, +the shell will suggest relevant complete options. + +In that case, we will create a program called `runcomplete`, a go program, +with a `func main()` and so, that will make the completion of the `run` +program. Once the `runcomplete` will be in a binary form, we could +`runcomplete -install` and that will add to our shell all the bash completion +options for `run`. + +So here it is: + + import "github.com/posener/complete" + + func main() { + + // create a Command object, that represents the command we want + // to complete. + run := complete.Command{ + + // Sub defines a list of sub commands of the program, + // this is recursive, since every command is of type command also. + Sub: complete.Commands{ + + // add a build sub command + "build": complete.Command { + + // define flags of the build sub command + Flags: complete.Flags{ + // build sub command has a flag '-cpus', which + // expects number of cpus after it. in that case + // anything could complete this flag. + "-cpus": complete.PredictAnything, + }, + }, + }, + + // define flags of the 'run' main command + Flags: complete.Flags{ + // a flag -o, which expects a file ending with .out after + // it, the tab completion will auto complete for files matching + // the given pattern. + "-o": complete.PredictFiles("*.out"), + }, + + // define global flags of the 'run' main command + // those will show up also when a sub command was entered in the + // command line + GlobalFlags: complete.Flags{ + + // a flag '-h' which does not expects anything after it + "-h": complete.PredictNothing, + }, + } + + // run the command completion, as part of the main() function. + // this triggers the autocompletion when needed. + // name must be exactly as the binary that we want to complete. + complete.New("run", run).Run() + } + +Self completing program + +In case that the program that we want to complete is written in go we +can make it self completing. +Here is an example: ./example/self/main.go . + +*/ +package complete diff --git a/vendor/github.com/posener/complete/go.mod b/vendor/github.com/posener/complete/go.mod index fef0c440d..6d82a9801 100644 --- a/vendor/github.com/posener/complete/go.mod +++ b/vendor/github.com/posener/complete/go.mod @@ -1,3 +1,8 @@ module github.com/posener/complete -require github.com/hashicorp/go-multierror v1.0.0 +require ( + github.com/hashicorp/go-multierror v1.0.0 + github.com/stretchr/testify v1.4.0 +) + +go 1.13 diff --git a/vendor/github.com/posener/complete/go.sum b/vendor/github.com/posener/complete/go.sum index d2f13301d..accaa27ad 100644 --- a/vendor/github.com/posener/complete/go.sum +++ b/vendor/github.com/posener/complete/go.sum @@ -1,4 +1,15 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +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/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/posener/complete/goreadme.json b/vendor/github.com/posener/complete/goreadme.json new file mode 100644 index 000000000..025ec76c9 --- /dev/null +++ b/vendor/github.com/posener/complete/goreadme.json @@ -0,0 +1,9 @@ +{ + "badges": { + "travis_ci": true, + "code_cov": true, + "golang_ci": true, + "go_doc": true, + "goreadme": true + } +} \ No newline at end of file diff --git a/vendor/github.com/posener/complete/match/file.go b/vendor/github.com/posener/complete/match/file.go deleted file mode 100644 index 051171e8a..000000000 --- a/vendor/github.com/posener/complete/match/file.go +++ /dev/null @@ -1,19 +0,0 @@ -package match - -import "strings" - -// File returns true if prefix can match the file -func File(file, prefix string) bool { - // special case for current directory completion - if file == "./" && (prefix == "." || prefix == "") { - return true - } - if prefix == "." && strings.HasPrefix(file, ".") { - return true - } - - file = strings.TrimPrefix(file, "./") - prefix = strings.TrimPrefix(prefix, "./") - - return strings.HasPrefix(file, prefix) -} diff --git a/vendor/github.com/posener/complete/match/match.go b/vendor/github.com/posener/complete/match/match.go deleted file mode 100644 index 812fcac96..000000000 --- a/vendor/github.com/posener/complete/match/match.go +++ /dev/null @@ -1,6 +0,0 @@ -package match - -// Match matches two strings -// it is used for comparing a term to the last typed -// word, the prefix, and see if it is a possible auto complete option. -type Match func(term, prefix string) bool diff --git a/vendor/github.com/posener/complete/match/prefix.go b/vendor/github.com/posener/complete/match/prefix.go deleted file mode 100644 index 9a01ba63a..000000000 --- a/vendor/github.com/posener/complete/match/prefix.go +++ /dev/null @@ -1,9 +0,0 @@ -package match - -import "strings" - -// Prefix is a simple Matcher, if the word is it's prefix, there is a match -// Match returns true if a has the prefix as prefix -func Prefix(long, prefix string) bool { - return strings.HasPrefix(long, prefix) -} diff --git a/vendor/github.com/posener/complete/predict_files.go b/vendor/github.com/posener/complete/predict_files.go index c8adf7e80..25ae2d514 100644 --- a/vendor/github.com/posener/complete/predict_files.go +++ b/vendor/github.com/posener/complete/predict_files.go @@ -5,8 +5,6 @@ import ( "os" "path/filepath" "strings" - - "github.com/posener/complete/match" ) // PredictDirs will search for directories in the given started to be typed @@ -53,7 +51,7 @@ func predictFiles(a Args, pattern string, allowFiles bool) []string { return nil } - dir := a.Directory() + dir := directory(a.Last) files := listFiles(dir, pattern, allowFiles) // add dir if match @@ -62,6 +60,19 @@ func predictFiles(a Args, pattern string, allowFiles bool) []string { return PredictFilesSet(files).Predict(a) } +// directory gives the directory of the given partial path +// in case that it is not, we fall back to the current directory. +func directory(path string) string { + if info, err := os.Stat(path); err == nil && info.IsDir() { + return fixPathForm(path, path) + } + dir := filepath.Dir(path) + if info, err := os.Stat(dir); err == nil && info.IsDir() { + return fixPathForm(path, dir) + } + return "./" +} + // PredictFilesSet predict according to file rules to a given set of file names func PredictFilesSet(files []string) PredictFunc { return func(a Args) (prediction []string) { @@ -70,7 +81,7 @@ func PredictFilesSet(files []string) PredictFunc { f = fixPathForm(a.Last, f) // test matching of file to the argument - if match.File(f, a.Last) { + if matchFile(f, a.Last) { prediction = append(prediction, f) } } @@ -106,3 +117,58 @@ func listFiles(dir, pattern string, allowFiles bool) []string { } return list } + +// MatchFile returns true if prefix can match the file +func matchFile(file, prefix string) bool { + // special case for current directory completion + if file == "./" && (prefix == "." || prefix == "") { + return true + } + if prefix == "." && strings.HasPrefix(file, ".") { + return true + } + + file = strings.TrimPrefix(file, "./") + prefix = strings.TrimPrefix(prefix, "./") + + return strings.HasPrefix(file, prefix) +} + +// fixPathForm changes a file name to a relative name +func fixPathForm(last string, file string) string { + // get wording directory for relative name + workDir, err := os.Getwd() + if err != nil { + return file + } + + abs, err := filepath.Abs(file) + if err != nil { + return file + } + + // if last is absolute, return path as absolute + if filepath.IsAbs(last) { + return fixDirPath(abs) + } + + rel, err := filepath.Rel(workDir, abs) + if err != nil { + return file + } + + // fix ./ prefix of path + if rel != "." && strings.HasPrefix(last, ".") { + rel = "./" + rel + } + + return fixDirPath(rel) +} + +func fixDirPath(path string) string { + info, err := os.Stat(path) + if err == nil && info.IsDir() && !strings.HasSuffix(path, "/") { + path += "/" + } + return path +} diff --git a/vendor/github.com/posener/complete/readme.md b/vendor/github.com/posener/complete/readme.md index 6d757ef82..dcc6c8932 100644 --- a/vendor/github.com/posener/complete/readme.md +++ b/vendor/github.com/posener/complete/readme.md @@ -1,28 +1,29 @@ # complete -A tool for bash writing bash completion in go, and bash completion for the go command line. - [![Build Status](https://travis-ci.org/posener/complete.svg?branch=master)](https://travis-ci.org/posener/complete) [![codecov](https://codecov.io/gh/posener/complete/branch/master/graph/badge.svg)](https://codecov.io/gh/posener/complete) [![golangci](https://golangci.com/badges/github.com/posener/complete.svg)](https://golangci.com/r/github.com/posener/complete) [![GoDoc](https://godoc.org/github.com/posener/complete?status.svg)](http://godoc.org/github.com/posener/complete) -[![Go Report Card](https://goreportcard.com/badge/github.com/posener/complete)](https://goreportcard.com/report/github.com/posener/complete) +[![goreadme](https://goreadme.herokuapp.com/badge/posener/complete.svg)](https://goreadme.herokuapp.com) + +Package complete provides a tool for bash writing bash completion in go, and bash completion for the go command line. Writing bash completion scripts is a hard work. This package provides an easy way to create bash completion scripts for any command, and also an easy way to install/uninstall the completion of the command. -## go command bash completion +#### Go Command Bash Completion -In [gocomplete](./gocomplete) there is an example for bash completion for the `go` command line. +In [./cmd/gocomplete](./cmd/gocomplete) there is an example for bash completion for the `go` command line. This is an example that uses the `complete` package on the `go` command - the `complete` package -can also be used to implement any completions, see [Usage](#usage). +can also be used to implement any completions, see #usage. -### Install +#### Install 1. Type in your shell: -``` + +```go go get -u github.com/posener/complete/gocomplete gocomplete -install ``` @@ -31,13 +32,13 @@ gocomplete -install Uninstall by `gocomplete -uninstall` -### Features +#### Features - Complete `go` command, including sub commands and all flags. - Complete packages names or `.go` files when necessary. - Complete test names after `-run` flag. -## complete package +#### Complete package Supported shells: @@ -45,7 +46,7 @@ Supported shells: - [x] zsh - [x] fish -### Usage +#### Usage Assuming you have program called `run` and you want to have bash completion for it, meaning, if you type `run` then space, then press the `Tab` key, @@ -53,7 +54,7 @@ the shell will suggest relevant complete options. In that case, we will create a program called `runcomplete`, a go program, with a `func main()` and so, that will make the completion of the `run` -program. Once the `runcomplete` will be in a binary form, we could +program. Once the `runcomplete` will be in a binary form, we could `runcomplete -install` and that will add to our shell all the bash completion options for `run`. @@ -110,9 +111,21 @@ func main() { } ``` -### Self completing program +#### Self completing program In case that the program that we want to complete is written in go we can make it self completing. +Here is an example: [./example/self/main.go](./example/self/main.go) . -Here is an [example](./example/self/main.go) +## Sub Packages + +* [cmd](./cmd): Package cmd used for command line options for the complete tool + +* [gocomplete](./gocomplete): Package main is complete tool for the go command line + +* [match](./match): Package match contains matchers that decide if to apply completion. + + +--- + +Created by [goreadme](https://github.com/apps/goreadme) diff --git a/vendor/github.com/posener/complete/test.sh b/vendor/github.com/posener/complete/test.sh deleted file mode 100644 index 56bfcf15d..000000000 --- a/vendor/github.com/posener/complete/test.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -set -e -echo "" > coverage.txt - -for d in $(go list ./... | grep -v vendor); do - go test -v -race -coverprofile=profile.out -covermode=atomic $d - if [ -f profile.out ]; then - cat profile.out >> coverage.txt - rm profile.out - fi -done \ No newline at end of file diff --git a/vendor/github.com/posener/complete/utils.go b/vendor/github.com/posener/complete/utils.go deleted file mode 100644 index 58b8b7927..000000000 --- a/vendor/github.com/posener/complete/utils.go +++ /dev/null @@ -1,46 +0,0 @@ -package complete - -import ( - "os" - "path/filepath" - "strings" -) - -// fixPathForm changes a file name to a relative name -func fixPathForm(last string, file string) string { - // get wording directory for relative name - workDir, err := os.Getwd() - if err != nil { - return file - } - - abs, err := filepath.Abs(file) - if err != nil { - return file - } - - // if last is absolute, return path as absolute - if filepath.IsAbs(last) { - return fixDirPath(abs) - } - - rel, err := filepath.Rel(workDir, abs) - if err != nil { - return file - } - - // fix ./ prefix of path - if rel != "." && strings.HasPrefix(last, ".") { - rel = "./" + rel - } - - return fixDirPath(rel) -} - -func fixDirPath(path string) string { - info, err := os.Stat(path) - if err == nil && info.IsDir() && !strings.HasSuffix(path, "/") { - path += "/" - } - return path -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 49de6c2b2..342c519ed 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -360,10 +360,10 @@ github.com/hashicorp/consul-template/signals github.com/hashicorp/consul-template/template github.com/hashicorp/consul-template/version github.com/hashicorp/consul-template/watch -# github.com/hashicorp/consul/api v1.4.0 +# github.com/hashicorp/consul/api v1.4.1-0.20200730220852-12f574c9de39 ## explicit github.com/hashicorp/consul/api -# github.com/hashicorp/consul/sdk v0.4.0 +# github.com/hashicorp/consul/sdk v0.5.0 ## explicit github.com/hashicorp/consul/sdk/freeport github.com/hashicorp/consul/sdk/testutil @@ -418,7 +418,7 @@ github.com/hashicorp/go-memdb # github.com/hashicorp/go-msgpack v1.1.5 ## explicit github.com/hashicorp/go-msgpack/codec -# github.com/hashicorp/go-multierror v1.0.1-0.20191120192120-72917a1559e1 +# github.com/hashicorp/go-multierror v1.1.0 ## explicit github.com/hashicorp/go-multierror # github.com/hashicorp/go-plugin v1.0.2-0.20191004171845-809113480b55 @@ -473,7 +473,7 @@ github.com/hashicorp/hcl/v2/json github.com/hashicorp/logutils # github.com/hashicorp/mdns v1.0.1 github.com/hashicorp/mdns -# github.com/hashicorp/memberlist v0.1.6 +# github.com/hashicorp/memberlist v0.2.2 ## explicit github.com/hashicorp/memberlist # github.com/hashicorp/net-rpc-msgpackrpc v0.0.0-20151116020338-a14192a58a69 @@ -489,7 +489,7 @@ github.com/hashicorp/raft # github.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea ## explicit github.com/hashicorp/raft-boltdb -# github.com/hashicorp/serf v0.8.5 +# github.com/hashicorp/serf v0.9.3 ## explicit github.com/hashicorp/serf/coordinate github.com/hashicorp/serf/serf @@ -556,7 +556,7 @@ github.com/mattn/go-shellwords github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/miekg/dns v1.1.26 github.com/miekg/dns -# github.com/mitchellh/cli v1.0.0 +# github.com/mitchellh/cli v1.1.0 ## explicit github.com/mitchellh/cli # github.com/mitchellh/colorstring v0.0.0-20150917214807-8631ce90f286 @@ -677,12 +677,11 @@ github.com/pierrec/lz4/internal/xxh32 github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib -# github.com/posener/complete v1.2.1 +# github.com/posener/complete v1.2.3 ## explicit github.com/posener/complete github.com/posener/complete/cmd github.com/posener/complete/cmd/install -github.com/posener/complete/match # github.com/prometheus/client_golang v1.4.0 ## explicit github.com/prometheus/client_golang/prometheus