diff --git a/vendor/git.autistici.org/ai3/go-common/README.md b/vendor/git.autistici.org/ai3/go-common/README.md new file mode 100644 index 0000000000000000000000000000000000000000..534838bfb168f391f01354ac1d74d976bd66489b --- /dev/null +++ b/vendor/git.autistici.org/ai3/go-common/README.md @@ -0,0 +1,22 @@ +ai3/go-common +=== + +Common code for ai3 services and tools. + +A quick overview of the contents: + +* [client](clientutil/) and [server](serverutil/) HTTP-based + "RPC" implementation, just JSON POST requests but with retries, + backoff, timeouts, tracing, etc. + +* [server implementation of a line-based protocol over a UNIX socket](unix/) + +* a [LDAP connection pool](ldap/) + +* a [password hashing library](pwhash/) that uses fancy advanced + crypto by default but is also backwards compatible with old + libc crypto. + +* utilities to [manage encryption keys](userenckey/), themselves + encrypted with a password and a KDF. + diff --git a/vendor/git.autistici.org/ai3/go-common/clientutil/balancer.go b/vendor/git.autistici.org/ai3/go-common/clientutil/balancer.go index f53b68e0313723d4f42eea04d779bf08d446e5c0..84633ac271887a35a7575805f8a6633b983949af 100644 --- a/vendor/git.autistici.org/ai3/go-common/clientutil/balancer.go +++ b/vendor/git.autistici.org/ai3/go-common/clientutil/balancer.go @@ -98,28 +98,35 @@ func newBalancedBackend(config *BackendConfig, resolver resolver) (*balancedBack // with a JSON-encoded request body. It will attempt to decode the // response body as JSON. func (b *balancedBackend) Call(ctx context.Context, shard, path string, req, resp interface{}) error { + // Serialize the request body. data, err := json.Marshal(req) if err != nil { return err } - var tg targetGenerator = b.backendTracker - if b.sharded { - if shard == "" { - return fmt.Errorf("call without shard to sharded service %s", b.baseURI.String()) - } - tg = newShardedGenerator(shard, b.baseURI.Host, b.resolver) + // Create the target sequence for this call. If there are multiple + // targets, reduce the timeout on each individual call accordingly to + // accomodate eventual failover. + seq, err := b.makeSequence(shard) + if err != nil { + return err + } + innerTimeout := 1 * time.Hour + if deadline, ok := ctx.Deadline(); ok { + innerTimeout = time.Until(deadline) / time.Duration(seq.Len()) } - seq := newSequence(tg) - b.log.Printf("%016x: initialized", seq.ID()) + // Call the backends in the sequence until one succeeds, with an + // exponential backoff policy controlled by the outer Context. var httpResp *http.Response err = backoff.Retry(func() error { req, rerr := b.newJSONRequest(path, shard, data) if rerr != nil { return rerr } - httpResp, rerr = b.do(ctx, seq, req) + innerCtx, cancel := context.WithTimeout(ctx, innerTimeout) + httpResp, rerr = b.do(innerCtx, seq, req) + cancel() return rerr }, backoff.WithContext(newExponentialBackOff(), ctx)) if err != nil { @@ -127,16 +134,34 @@ func (b *balancedBackend) Call(ctx context.Context, shard, path string, req, res } defer httpResp.Body.Close() // nolint + // Decode the response. if httpResp.Header.Get("Content-Type") != "application/json" { return errors.New("not a JSON response") } - if resp == nil { return nil } return json.NewDecoder(httpResp.Body).Decode(resp) } +// Initialize a new target sequence. +func (b *balancedBackend) makeSequence(shard string) (*sequence, error) { + var tg targetGenerator = b.backendTracker + if b.sharded { + if shard == "" { + return nil, fmt.Errorf("call without shard to sharded service %s", b.baseURI.String()) + } + tg = newShardedGenerator(shard, b.baseURI.Host, b.resolver) + } + + seq := newSequence(tg) + if seq.Len() == 0 { + return nil, errNoTargets + } + b.log.Printf("%016x: initialized", seq.ID()) + return seq, nil +} + // Return the URI to be used for the request. This is used both in the // Host HTTP header and as the TLS server name used to pick a server // certificate (if using TLS). @@ -213,6 +238,8 @@ func newSequence(tg targetGenerator) *sequence { func (s *sequence) ID() uint64 { return s.id } +func (s *sequence) Len() int { return len(s.targets) } + func (s *sequence) reloadTargets() { targets := s.tg.getTargets() if len(targets) > 0 { diff --git a/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go b/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go index df6144b7dd054b4dfde6640d95351f872050275a..0cd132b82e0de462fa45ced20d2f3da0d1176f26 100644 --- a/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go +++ b/vendor/git.autistici.org/ai3/go-common/tracing/tracing.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strconv" "sync" openzipkin "github.com/openzipkin/zipkin-go" @@ -31,6 +32,7 @@ const globalTracingConfigPath = "/etc/tracing/client.conf" type tracingConfig struct { ReportURL string `json:"report_url"` + Sample string `json:"sample"` } // Read the global tracing configuration file. Its location is @@ -91,6 +93,9 @@ func init() { } func initTracing(endpointAddr string) { + if !Enabled { + return + } initOnce.Do(func() { localEndpoint, err := openzipkin.NewEndpoint(getServiceName(), endpointAddr) if err != nil { @@ -100,9 +105,23 @@ func initTracing(endpointAddr string) { reporter := zipkinHTTP.NewReporter(config.ReportURL) ze := zipkin.NewExporter(reporter, localEndpoint) - trace.RegisterExporter(ze) - trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) + + var tc trace.Config + switch config.Sample { + case "", "always": + tc.DefaultSampler = trace.AlwaysSample() + case "never": + tc.DefaultSampler = trace.NeverSample() + default: + frac, err := strconv.ParseFloat(config.Sample, 64) + if err != nil { + log.Printf("warning: error in tracing configuration: sample: %v, tracing disabled", err) + return + } + tc.DefaultSampler = trace.ProbabilitySampler(frac) + } + trace.ApplyConfig(tc) log.Printf("tracing enabled (report_url %s)", config.ReportURL) @@ -110,6 +129,11 @@ func initTracing(endpointAddr string) { }) } +// Init tracing support, if not using WrapHandler. +func Init() { + initTracing("") +} + // WrapTransport optionally wraps a http.RoundTripper with OpenCensus // tracing functionality, if it is globally enabled. func WrapTransport(t http.RoundTripper) http.RoundTripper { @@ -120,7 +144,7 @@ func WrapTransport(t http.RoundTripper) http.RoundTripper { } // WrapHandler wraps a http.Handler with OpenCensus tracing -// functionality, if globally enabled. +// functionality, if globally enabled. Automatically calls Init(). func WrapHandler(h http.Handler, endpointAddr string) http.Handler { if Enabled { initTracing(endpointAddr) diff --git a/vendor/vendor.json b/vendor/vendor.json index a62ab612faa86ff1c972a54961baaf358e915715..cfdc0f14c72981366f5b98f84fee045400922bd9 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -3,28 +3,28 @@ "ignore": "test", "package": [ { - "checksumSHA1": "pLvPnUablirQucyALgrso9hLG4E=", + "checksumSHA1": "mqNsLVty/oAcBDXv2DZeqMtGeaY=", "path": "git.autistici.org/ai3/go-common", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "0868f2647fefb9c3855bb6242aae8aab6d0ddc6d", + "revisionTime": "2019-01-29T12:17:45Z" }, { - "checksumSHA1": "1ChQcW9Biu/AgiKjsbJFg/+WhjQ=", + "checksumSHA1": "hKJhn/0mTkaYIHwFTy+W9TLr09M=", "path": "git.autistici.org/ai3/go-common/clientutil", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "0868f2647fefb9c3855bb6242aae8aab6d0ddc6d", + "revisionTime": "2019-01-29T12:17:45Z" }, { "checksumSHA1": "TKGUNmKxj7KH3qhwiCh/6quUnwc=", "path": "git.autistici.org/ai3/go-common/serverutil", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "0868f2647fefb9c3855bb6242aae8aab6d0ddc6d", + "revisionTime": "2019-01-29T12:17:45Z" }, { - "checksumSHA1": "WvuSF0pz3rk7bu+5g9lqTqq97Ow=", + "checksumSHA1": "y5pRYZ/NhfEOCFslPEuUZTYXcro=", "path": "git.autistici.org/ai3/go-common/tracing", - "revision": "1f95fcdd58ebf63d338f05ceae29d2de811a2d2f", - "revisionTime": "2018-11-18T16:11:30Z" + "revision": "0868f2647fefb9c3855bb6242aae8aab6d0ddc6d", + "revisionTime": "2019-01-29T12:17:45Z" }, { "checksumSHA1": "6D5Xt9WoGSeTJE3XFw6P2/nKYrQ=",