summaryrefslogtreecommitdiff
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/Microsoft/hcsshim/mksyscall_windows.go943
-rw-r--r--vendor/github.com/containernetworking/cni/libcni/api.go230
-rw-r--r--vendor/github.com/containernetworking/cni/libcni/conf.go4
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/invoke/args.go2
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/types/args.go2
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/types/types.go25
-rw-r--r--vendor/github.com/containernetworking/cni/pkg/utils/utils.go51
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/example_changes.go97
-rw-r--r--vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go411
-rw-r--r--vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go32
-rw-r--r--vendor/github.com/docker/docker/pkg/archive/example_changes.go97
-rw-r--r--vendor/github.com/json-iterator/go/iter.go27
-rw-r--r--vendor/github.com/json-iterator/go/iter_array.go10
-rw-r--r--vendor/github.com/json-iterator/go/iter_object.go24
-rw-r--r--vendor/github.com/json-iterator/go/iter_skip_sloppy.go19
-rw-r--r--vendor/github.com/json-iterator/go/reflect.go5
-rw-r--r--vendor/github.com/json-iterator/go/reflect_extension.go2
-rw-r--r--vendor/github.com/json-iterator/go/reflect_map.go4
-rw-r--r--vendor/github.com/json-iterator/go/reflect_marshaler.go12
-rw-r--r--vendor/github.com/json-iterator/go/reflect_struct_decoder.go44
-rw-r--r--vendor/github.com/klauspost/compress/flate/gen.go265
-rw-r--r--vendor/github.com/klauspost/cpuid/private-gen.go476
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md5
-rw-r--r--vendor/github.com/onsi/gomega/go.mod3
-rw-r--r--vendor/github.com/onsi/gomega/go.sum4
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/.travis.yml9
-rw-r--r--vendor/github.com/uber/jaeger-client-go/CHANGELOG.md39
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Gopkg.lock125
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Gopkg.toml2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/Makefile3
-rw-r--r--vendor/github.com/uber/jaeger-client-go/README.md23
-rw-r--r--vendor/github.com/uber/jaeger-client-go/config/config.go4
-rw-r--r--vendor/github.com/uber/jaeger-client-go/config/config_env.go24
-rw-r--r--vendor/github.com/uber/jaeger-client-go/constants.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/metrics.go20
-rw-r--r--vendor/github.com/uber/jaeger-client-go/propagation.go8
-rw-r--r--vendor/github.com/uber/jaeger-client-go/reporter.go2
-rw-r--r--vendor/github.com/uber/jaeger-client-go/sampler.go446
-rw-r--r--vendor/github.com/uber/jaeger-client-go/sampler_remote.go334
-rw-r--r--vendor/github.com/uber/jaeger-client-go/sampler_remote_options.go (renamed from vendor/github.com/uber/jaeger-client-go/sampler_options.go)71
-rw-r--r--vendor/github.com/uber/jaeger-client-go/sampler_v2.go93
-rw-r--r--vendor/github.com/uber/jaeger-client-go/span.go144
-rw-r--r--vendor/github.com/uber/jaeger-client-go/span_context.go (renamed from vendor/github.com/uber/jaeger-client-go/context.go)161
-rw-r--r--vendor/github.com/uber/jaeger-client-go/tracer.go127
-rw-r--r--vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go93
-rw-r--r--vendor/github.com/uber/jaeger-client-go/zipkin.go5
-rw-r--r--vendor/github.com/ulikunitz/xz/example.go40
49 files changed, 2058 insertions, 2515 deletions
diff --git a/vendor/github.com/Microsoft/hcsshim/mksyscall_windows.go b/vendor/github.com/Microsoft/hcsshim/mksyscall_windows.go
deleted file mode 100644
index 7647734de..000000000
--- a/vendor/github.com/Microsoft/hcsshim/mksyscall_windows.go
+++ /dev/null
@@ -1,943 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-/*
-mksyscall_windows generates windows system call bodies
-
-It parses all files specified on command line containing function
-prototypes (like syscall_windows.go) and prints system call bodies
-to standard output.
-
-The prototypes are marked by lines beginning with "//sys" and read
-like func declarations if //sys is replaced by func, but:
-
-* The parameter lists must give a name for each argument. This
- includes return parameters.
-
-* The parameter lists must give a type for each argument:
- the (x, y, z int) shorthand is not allowed.
-
-* If the return parameter is an error number, it must be named err.
-
-* If go func name needs to be different from it's winapi dll name,
- the winapi name could be specified at the end, after "=" sign, like
- //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
-
-* Each function that returns err needs to supply a condition, that
- return value of winapi will be tested against to detect failure.
- This would set err to windows "last-error", otherwise it will be nil.
- The value can be provided at end of //sys declaration, like
- //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
- and is [failretval==0] by default.
-
-Usage:
- mksyscall_windows [flags] [path ...]
-
-The flags are:
- -output
- Specify output file name (outputs to console if blank).
- -trace
- Generate print statement after every syscall.
-*/
-package main
-
-import (
- "bufio"
- "bytes"
- "errors"
- "flag"
- "fmt"
- "go/format"
- "go/parser"
- "go/token"
- "io"
- "io/ioutil"
- "log"
- "os"
- "path/filepath"
- "runtime"
- "sort"
- "strconv"
- "strings"
- "text/template"
-)
-
-var (
- filename = flag.String("output", "", "output file name (standard output if omitted)")
- printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
- systemDLL = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
- winio = flag.Bool("winio", false, "import go-winio")
-)
-
-func trim(s string) string {
- return strings.Trim(s, " \t")
-}
-
-var packageName string
-
-func packagename() string {
- return packageName
-}
-
-func syscalldot() string {
- if packageName == "syscall" {
- return ""
- }
- return "syscall."
-}
-
-// Param is function parameter
-type Param struct {
- Name string
- Type string
- fn *Fn
- tmpVarIdx int
-}
-
-// tmpVar returns temp variable name that will be used to represent p during syscall.
-func (p *Param) tmpVar() string {
- if p.tmpVarIdx < 0 {
- p.tmpVarIdx = p.fn.curTmpVarIdx
- p.fn.curTmpVarIdx++
- }
- return fmt.Sprintf("_p%d", p.tmpVarIdx)
-}
-
-// BoolTmpVarCode returns source code for bool temp variable.
-func (p *Param) BoolTmpVarCode() string {
- const code = `var %s uint32
- if %s {
- %s = 1
- } else {
- %s = 0
- }`
- tmp := p.tmpVar()
- return fmt.Sprintf(code, tmp, p.Name, tmp, tmp)
-}
-
-// SliceTmpVarCode returns source code for slice temp variable.
-func (p *Param) SliceTmpVarCode() string {
- const code = `var %s *%s
- if len(%s) > 0 {
- %s = &%s[0]
- }`
- tmp := p.tmpVar()
- return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name)
-}
-
-// StringTmpVarCode returns source code for string temp variable.
-func (p *Param) StringTmpVarCode() string {
- errvar := p.fn.Rets.ErrorVarName()
- if errvar == "" {
- errvar = "_"
- }
- tmp := p.tmpVar()
- const code = `var %s %s
- %s, %s = %s(%s)`
- s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name)
- if errvar == "-" {
- return s
- }
- const morecode = `
- if %s != nil {
- return
- }`
- return s + fmt.Sprintf(morecode, errvar)
-}
-
-// TmpVarCode returns source code for temp variable.
-func (p *Param) TmpVarCode() string {
- switch {
- case p.Type == "bool":
- return p.BoolTmpVarCode()
- case strings.HasPrefix(p.Type, "[]"):
- return p.SliceTmpVarCode()
- default:
- return ""
- }
-}
-
-// TmpVarHelperCode returns source code for helper's temp variable.
-func (p *Param) TmpVarHelperCode() string {
- if p.Type != "string" {
- return ""
- }
- return p.StringTmpVarCode()
-}
-
-// SyscallArgList returns source code fragments representing p parameter
-// in syscall. Slices are translated into 2 syscall parameters: pointer to
-// the first element and length.
-func (p *Param) SyscallArgList() []string {
- t := p.HelperType()
- var s string
- switch {
- case t[0] == '*':
- s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name)
- case t == "bool":
- s = p.tmpVar()
- case strings.HasPrefix(t, "[]"):
- return []string{
- fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()),
- fmt.Sprintf("uintptr(len(%s))", p.Name),
- }
- default:
- s = p.Name
- }
- return []string{fmt.Sprintf("uintptr(%s)", s)}
-}
-
-// IsError determines if p parameter is used to return error.
-func (p *Param) IsError() bool {
- return p.Name == "err" && p.Type == "error"
-}
-
-// HelperType returns type of parameter p used in helper function.
-func (p *Param) HelperType() string {
- if p.Type == "string" {
- return p.fn.StrconvType()
- }
- return p.Type
-}
-
-// join concatenates parameters ps into a string with sep separator.
-// Each parameter is converted into string by applying fn to it
-// before conversion.
-func join(ps []*Param, fn func(*Param) string, sep string) string {
- if len(ps) == 0 {
- return ""
- }
- a := make([]string, 0)
- for _, p := range ps {
- a = append(a, fn(p))
- }
- return strings.Join(a, sep)
-}
-
-// Rets describes function return parameters.
-type Rets struct {
- Name string
- Type string
- ReturnsError bool
- FailCond string
-}
-
-// ErrorVarName returns error variable name for r.
-func (r *Rets) ErrorVarName() string {
- if r.ReturnsError {
- return "err"
- }
- if r.Type == "error" {
- return r.Name
- }
- return ""
-}
-
-// ToParams converts r into slice of *Param.
-func (r *Rets) ToParams() []*Param {
- ps := make([]*Param, 0)
- if len(r.Name) > 0 {
- ps = append(ps, &Param{Name: r.Name, Type: r.Type})
- }
- if r.ReturnsError {
- ps = append(ps, &Param{Name: "err", Type: "error"})
- }
- return ps
-}
-
-// List returns source code of syscall return parameters.
-func (r *Rets) List() string {
- s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ")
- if len(s) > 0 {
- s = "(" + s + ")"
- }
- return s
-}
-
-// PrintList returns source code of trace printing part correspondent
-// to syscall return values.
-func (r *Rets) PrintList() string {
- return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
-}
-
-// SetReturnValuesCode returns source code that accepts syscall return values.
-func (r *Rets) SetReturnValuesCode() string {
- if r.Name == "" && !r.ReturnsError {
- return ""
- }
- retvar := "r0"
- if r.Name == "" {
- retvar = "r1"
- }
- errvar := "_"
- if r.ReturnsError {
- errvar = "e1"
- }
- return fmt.Sprintf("%s, _, %s := ", retvar, errvar)
-}
-
-func (r *Rets) useLongHandleErrorCode(retvar string) string {
- const code = `if %s {
- if e1 != 0 {
- err = errnoErr(e1)
- } else {
- err = %sEINVAL
- }
- }`
- cond := retvar + " == 0"
- if r.FailCond != "" {
- cond = strings.Replace(r.FailCond, "failretval", retvar, 1)
- }
- return fmt.Sprintf(code, cond, syscalldot())
-}
-
-// SetErrorCode returns source code that sets return parameters.
-func (r *Rets) SetErrorCode() string {
- const code = `if r0 != 0 {
- %s = %sErrno(r0)
- }`
- const hrCode = `if int32(r0) < 0 {
- if r0&0x1fff0000 == 0x00070000 {
- r0 &= 0xffff
- }
- %s = %sErrno(r0)
- }`
- if r.Name == "" && !r.ReturnsError {
- return ""
- }
- if r.Name == "" {
- return r.useLongHandleErrorCode("r1")
- }
- if r.Type == "error" {
- if r.Name == "hr" {
- return fmt.Sprintf(hrCode, r.Name, syscalldot())
- } else {
- return fmt.Sprintf(code, r.Name, syscalldot())
- }
- }
- s := ""
- switch {
- case r.Type[0] == '*':
- s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type)
- case r.Type == "bool":
- s = fmt.Sprintf("%s = r0 != 0", r.Name)
- default:
- s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type)
- }
- if !r.ReturnsError {
- return s
- }
- return s + "\n\t" + r.useLongHandleErrorCode(r.Name)
-}
-
-// Fn describes syscall function.
-type Fn struct {
- Name string
- Params []*Param
- Rets *Rets
- PrintTrace bool
- confirmproc bool
- dllname string
- dllfuncname string
- src string
- // TODO: get rid of this field and just use parameter index instead
- curTmpVarIdx int // insure tmp variables have uniq names
-}
-
-// extractParams parses s to extract function parameters.
-func extractParams(s string, f *Fn) ([]*Param, error) {
- s = trim(s)
- if s == "" {
- return nil, nil
- }
- a := strings.Split(s, ",")
- ps := make([]*Param, len(a))
- for i := range ps {
- s2 := trim(a[i])
- b := strings.Split(s2, " ")
- if len(b) != 2 {
- b = strings.Split(s2, "\t")
- if len(b) != 2 {
- return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"")
- }
- }
- ps[i] = &Param{
- Name: trim(b[0]),
- Type: trim(b[1]),
- fn: f,
- tmpVarIdx: -1,
- }
- }
- return ps, nil
-}
-
-// extractSection extracts text out of string s starting after start
-// and ending just before end. found return value will indicate success,
-// and prefix, body and suffix will contain correspondent parts of string s.
-func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) {
- s = trim(s)
- if strings.HasPrefix(s, string(start)) {
- // no prefix
- body = s[1:]
- } else {
- a := strings.SplitN(s, string(start), 2)
- if len(a) != 2 {
- return "", "", s, false
- }
- prefix = a[0]
- body = a[1]
- }
- a := strings.SplitN(body, string(end), 2)
- if len(a) != 2 {
- return "", "", "", false
- }
- return prefix, a[0], a[1], true
-}
-
-// newFn parses string s and return created function Fn.
-func newFn(s string) (*Fn, error) {
- s = trim(s)
- f := &Fn{
- Rets: &Rets{},
- src: s,
- PrintTrace: *printTraceFlag,
- }
- // function name and args
- prefix, body, s, found := extractSection(s, '(', ')')
- if !found || prefix == "" {
- return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"")
- }
- f.Name = prefix
- var err error
- f.Params, err = extractParams(body, f)
- if err != nil {
- return nil, err
- }
- // return values
- _, body, s, found = extractSection(s, '(', ')')
- if found {
- r, err := extractParams(body, f)
- if err != nil {
- return nil, err
- }
- switch len(r) {
- case 0:
- case 1:
- if r[0].IsError() {
- f.Rets.ReturnsError = true
- } else {
- f.Rets.Name = r[0].Name
- f.Rets.Type = r[0].Type
- }
- case 2:
- if !r[1].IsError() {
- return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"")
- }
- f.Rets.ReturnsError = true
- f.Rets.Name = r[0].Name
- f.Rets.Type = r[0].Type
- default:
- return nil, errors.New("Too many return values in \"" + f.src + "\"")
- }
- }
- // fail condition
- _, body, s, found = extractSection(s, '[', ']')
- if found {
- f.Rets.FailCond = body
- }
- // dll and dll function names
- s = trim(s)
- if s == "" {
- return f, nil
- }
- if !strings.HasPrefix(s, "=") {
- return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
- }
- s = trim(s[1:])
- a := strings.Split(s, ".")
- switch len(a) {
- case 1:
- f.dllfuncname = a[0]
- case 2:
- f.dllname = a[0]
- f.dllfuncname = a[1]
- default:
- return nil, errors.New("Could not extract dll name from \"" + f.src + "\"")
- }
- if f.dllfuncname[len(f.dllfuncname)-1] == '?' {
- f.confirmproc = true
- f.dllfuncname = f.dllfuncname[0 : len(f.dllfuncname)-1]
- }
- return f, nil
-}
-
-// DLLName returns DLL name for function f.
-func (f *Fn) DLLName() string {
- if f.dllname == "" {
- return "kernel32"
- }
- return f.dllname
-}
-
-// DLLName returns DLL function name for function f.
-func (f *Fn) DLLFuncName() string {
- if f.dllfuncname == "" {
- return f.Name
- }
- return f.dllfuncname
-}
-
-func (f *Fn) ConfirmProc() bool {
- return f.confirmproc
-}
-
-// ParamList returns source code for function f parameters.
-func (f *Fn) ParamList() string {
- return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ")
-}
-
-// HelperParamList returns source code for helper function f parameters.
-func (f *Fn) HelperParamList() string {
- return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ")
-}
-
-// ParamPrintList returns source code of trace printing part correspondent
-// to syscall input parameters.
-func (f *Fn) ParamPrintList() string {
- return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `)
-}
-
-// ParamCount return number of syscall parameters for function f.
-func (f *Fn) ParamCount() int {
- n := 0
- for _, p := range f.Params {
- n += len(p.SyscallArgList())
- }
- return n
-}
-
-// SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/...
-// to use. It returns parameter count for correspondent SyscallX function.
-func (f *Fn) SyscallParamCount() int {
- n := f.ParamCount()
- switch {
- case n <= 3:
- return 3
- case n <= 6:
- return 6
- case n <= 9:
- return 9
- case n <= 12:
- return 12
- case n <= 15:
- return 15
- default:
- panic("too many arguments to system call")
- }
-}
-
-// Syscall determines which SyscallX function to use for function f.
-func (f *Fn) Syscall() string {
- c := f.SyscallParamCount()
- if c == 3 {
- return syscalldot() + "Syscall"
- }
- return syscalldot() + "Syscall" + strconv.Itoa(c)
-}
-
-// SyscallParamList returns source code for SyscallX parameters for function f.
-func (f *Fn) SyscallParamList() string {
- a := make([]string, 0)
- for _, p := range f.Params {
- a = append(a, p.SyscallArgList()...)
- }
- for len(a) < f.SyscallParamCount() {
- a = append(a, "0")
- }
- return strings.Join(a, ", ")
-}
-
-// HelperCallParamList returns source code of call into function f helper.
-func (f *Fn) HelperCallParamList() string {
- a := make([]string, 0, len(f.Params))
- for _, p := range f.Params {
- s := p.Name
- if p.Type == "string" {
- s = p.tmpVar()
- }
- a = append(a, s)
- }
- return strings.Join(a, ", ")
-}
-
-// IsUTF16 is true, if f is W (utf16) function. It is false
-// for all A (ascii) functions.
-func (_ *Fn) IsUTF16() bool {
- return true
-}
-
-// StrconvFunc returns name of Go string to OS string function for f.
-func (f *Fn) StrconvFunc() string {
- if f.IsUTF16() {
- return syscalldot() + "UTF16PtrFromString"
- }
- return syscalldot() + "BytePtrFromString"
-}
-
-// StrconvType returns Go type name used for OS string for f.
-func (f *Fn) StrconvType() string {
- if f.IsUTF16() {
- return "*uint16"
- }
- return "*byte"
-}
-
-// HasStringParam is true, if f has at least one string parameter.
-// Otherwise it is false.
-func (f *Fn) HasStringParam() bool {
- for _, p := range f.Params {
- if p.Type == "string" {
- return true
- }
- }
- return false
-}
-
-var uniqDllFuncName = make(map[string]bool)
-
-// IsNotDuplicate is true if f is not a duplicated function
-func (f *Fn) IsNotDuplicate() bool {
- funcName := f.DLLFuncName()
- if uniqDllFuncName[funcName] == false {
- uniqDllFuncName[funcName] = true
- return true
- }
- return false
-}
-
-// HelperName returns name of function f helper.
-func (f *Fn) HelperName() string {
- if !f.HasStringParam() {
- return f.Name
- }
- return "_" + f.Name
-}
-
-// Source files and functions.
-type Source struct {
- Funcs []*Fn
- Files []string
- StdLibImports []string
- ExternalImports []string
-}
-
-func (src *Source) Import(pkg string) {
- src.StdLibImports = append(src.StdLibImports, pkg)
- sort.Strings(src.StdLibImports)
-}
-
-func (src *Source) ExternalImport(pkg string) {
- src.ExternalImports = append(src.ExternalImports, pkg)
- sort.Strings(src.ExternalImports)
-}
-
-// ParseFiles parses files listed in fs and extracts all syscall
-// functions listed in sys comments. It returns source files
-// and functions collection *Source if successful.
-func ParseFiles(fs []string) (*Source, error) {
- src := &Source{
- Funcs: make([]*Fn, 0),
- Files: make([]string, 0),
- StdLibImports: []string{
- "unsafe",
- },
- ExternalImports: make([]string, 0),
- }
- for _, file := range fs {
- if err := src.ParseFile(file); err != nil {
- return nil, err
- }
- }
- return src, nil
-}
-
-// DLLs return dll names for a source set src.
-func (src *Source) DLLs() []string {
- uniq := make(map[string]bool)
- r := make([]string, 0)
- for _, f := range src.Funcs {
- name := f.DLLName()
- if _, found := uniq[name]; !found {
- uniq[name] = true
- r = append(r, name)
- }
- }
- return r
-}
-
-// ParseFile adds additional file path to a source set src.
-func (src *Source) ParseFile(path string) error {
- file, err := os.Open(path)
- if err != nil {
- return err
- }
- defer file.Close()
-
- s := bufio.NewScanner(file)
- for s.Scan() {
- t := trim(s.Text())
- if len(t) < 7 {
- continue
- }
- if !strings.HasPrefix(t, "//sys") {
- continue
- }
- t = t[5:]
- if !(t[0] == ' ' || t[0] == '\t') {
- continue
- }
- f, err := newFn(t[1:])
- if err != nil {
- return err
- }
- src.Funcs = append(src.Funcs, f)
- }
- if err := s.Err(); err != nil {
- return err
- }
- src.Files = append(src.Files, path)
-
- // get package name
- fset := token.NewFileSet()
- _, err = file.Seek(0, 0)
- if err != nil {
- return err
- }
- pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly)
- if err != nil {
- return err
- }
- packageName = pkg.Name.Name
-
- return nil
-}
-
-// IsStdRepo returns true if src is part of standard library.
-func (src *Source) IsStdRepo() (bool, error) {
- if len(src.Files) == 0 {
- return false, errors.New("no input files provided")
- }
- abspath, err := filepath.Abs(src.Files[0])
- if err != nil {
- return false, err
- }
- goroot := runtime.GOROOT()
- if runtime.GOOS == "windows" {
- abspath = strings.ToLower(abspath)
- goroot = strings.ToLower(goroot)
- }
- sep := string(os.PathSeparator)
- if !strings.HasSuffix(goroot, sep) {
- goroot += sep
- }
- return strings.HasPrefix(abspath, goroot), nil
-}
-
-// Generate output source file from a source set src.
-func (src *Source) Generate(w io.Writer) error {
- const (
- pkgStd = iota // any package in std library
- pkgXSysWindows // x/sys/windows package
- pkgOther
- )
- isStdRepo, err := src.IsStdRepo()
- if err != nil {
- return err
- }
- var pkgtype int
- switch {
- case isStdRepo:
- pkgtype = pkgStd
- case packageName == "windows":
- // TODO: this needs better logic than just using package name
- pkgtype = pkgXSysWindows
- default:
- pkgtype = pkgOther
- }
- if *systemDLL {
- switch pkgtype {
- case pkgStd:
- src.Import("internal/syscall/windows/sysdll")
- case pkgXSysWindows:
- default:
- src.ExternalImport("golang.org/x/sys/windows")
- }
- }
- if *winio {
- src.ExternalImport("github.com/Microsoft/go-winio")
- }
- if packageName != "syscall" {
- src.Import("syscall")
- }
- funcMap := template.FuncMap{
- "packagename": packagename,
- "syscalldot": syscalldot,
- "newlazydll": func(dll string) string {
- arg := "\"" + dll + ".dll\""
- if !*systemDLL {
- return syscalldot() + "NewLazyDLL(" + arg + ")"
- }
- if strings.HasPrefix(dll, "api_") || strings.HasPrefix(dll, "ext_") {
- arg = strings.Replace(arg, "_", "-", -1)
- }
- switch pkgtype {
- case pkgStd:
- return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
- case pkgXSysWindows:
- return "NewLazySystemDLL(" + arg + ")"
- default:
- return "windows.NewLazySystemDLL(" + arg + ")"
- }
- },
- }
- t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
- err = t.Execute(w, src)
- if err != nil {
- return errors.New("Failed to execute template: " + err.Error())
- }
- return nil
-}
-
-func usage() {
- fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n")
- flag.PrintDefaults()
- os.Exit(1)
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
- if len(flag.Args()) <= 0 {
- fmt.Fprintf(os.Stderr, "no files to parse provided\n")
- usage()
- }
-
- src, err := ParseFiles(flag.Args())
- if err != nil {
- log.Fatal(err)
- }
-
- var buf bytes.Buffer
- if err := src.Generate(&buf); err != nil {
- log.Fatal(err)
- }
-
- data, err := format.Source(buf.Bytes())
- if err != nil {
- log.Fatal(err)
- }
- if *filename == "" {
- _, err = os.Stdout.Write(data)
- } else {
- err = ioutil.WriteFile(*filename, data, 0644)
- }
- if err != nil {
- log.Fatal(err)
- }
-}
-
-// TODO: use println instead to print in the following template
-const srcTemplate = `
-
-{{define "main"}}// Code generated mksyscall_windows.exe DO NOT EDIT
-
-package {{packagename}}
-
-import (
-{{range .StdLibImports}}"{{.}}"
-{{end}}
-
-{{range .ExternalImports}}"{{.}}"
-{{end}}
-)
-
-var _ unsafe.Pointer
-
-// Do the interface allocations only once for common
-// Errno values.
-const (
- errnoERROR_IO_PENDING = 997
-)
-
-var (
- errERROR_IO_PENDING error = {{syscalldot}}Errno(errnoERROR_IO_PENDING)
-)
-
-// errnoErr returns common boxed Errno values, to prevent
-// allocations at runtime.
-func errnoErr(e {{syscalldot}}Errno) error {
- switch e {
- case 0:
- return nil
- case errnoERROR_IO_PENDING:
- return errERROR_IO_PENDING
- }
- // TODO: add more here, after collecting data on the common
- // error values see on Windows. (perhaps when running
- // all.bat?)
- return e
-}
-
-var (
-{{template "dlls" .}}
-{{template "funcnames" .}})
-{{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}}
-{{end}}
-
-{{/* help functions */}}
-
-{{define "dlls"}}{{range .DLLs}} mod{{.}} = {{newlazydll .}}
-{{end}}{{end}}
-
-{{define "funcnames"}}{{range .Funcs}}{{if .IsNotDuplicate}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}"){{end}}
-{{end}}{{end}}
-
-{{define "helperbody"}}
-func {{.Name}}({{.ParamList}}) {{template "results" .}}{
-{{template "helpertmpvars" .}} return {{.HelperName}}({{.HelperCallParamList}})
-}
-{{end}}
-
-{{define "funcbody"}}
-func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{
-{{template "tmpvars" .}} {{template "syscallcheck" .}}{{template "syscall" .}}
-{{template "seterror" .}}{{template "printtrace" .}} return
-}
-{{end}}
-
-{{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}} {{.TmpVarHelperCode}}
-{{end}}{{end}}{{end}}
-
-{{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}}
-{{end}}{{end}}{{end}}
-
-{{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}}
-
-{{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}}
-
-{{define "syscallcheck"}}{{if .ConfirmProc}}if {{.Rets.ErrorVarName}} = proc{{.DLLFuncName}}.Find(); {{.Rets.ErrorVarName}} != nil {
- return
-}
-{{end}}{{end}}
-
-
-{{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}}
-{{end}}{{end}}
-
-{{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n")
-{{end}}{{end}}
-
-`
diff --git a/vendor/github.com/containernetworking/cni/libcni/api.go b/vendor/github.com/containernetworking/cni/libcni/api.go
index 0f14d3427..22b111742 100644
--- a/vendor/github.com/containernetworking/cni/libcni/api.go
+++ b/vendor/github.com/containernetworking/cni/libcni/api.go
@@ -25,6 +25,7 @@ import (
"github.com/containernetworking/cni/pkg/invoke"
"github.com/containernetworking/cni/pkg/types"
+ "github.com/containernetworking/cni/pkg/utils"
"github.com/containernetworking/cni/pkg/version"
)
@@ -32,6 +33,10 @@ var (
CacheDir = "/var/lib/cni"
)
+const (
+ CNICacheV1 = "cniCacheV1"
+)
+
// A RuntimeConf holds the arguments to one invocation of a CNI plugin
// excepting the network configuration, with the nested exception that
// the `runtimeConfig` from the network configuration is included
@@ -48,7 +53,7 @@ type RuntimeConf struct {
// to the plugin
CapabilityArgs map[string]interface{}
- // A cache directory in which to library data. Defaults to CacheDir
+ // DEPRECATED. Will be removed in a future release.
CacheDir string
}
@@ -70,19 +75,22 @@ type CNI interface {
CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
+ GetNetworkListCachedConfig(net *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
+ GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error)
ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
}
type CNIConfig struct {
- Path []string
- exec invoke.Exec
+ Path []string
+ exec invoke.Exec
+ cacheDir string
}
// CNIConfig implements the CNI interface
@@ -92,9 +100,18 @@ var _ CNI = &CNIConfig{}
// in the given paths and use the given exec interface to run those plugins,
// or if the exec interface is not given, will use a default exec handler.
func NewCNIConfig(path []string, exec invoke.Exec) *CNIConfig {
+ return NewCNIConfigWithCacheDir(path, "", exec)
+}
+
+// NewCNIConfigWithCacheDir returns a new CNIConfig object that will search for plugins
+// in the given paths use the given exec interface to run those plugins,
+// or if the exec interface is not given, will use a default exec handler.
+// The given cache directory will be used for temporary data storage when needed.
+func NewCNIConfigWithCacheDir(path []string, cacheDir string, exec invoke.Exec) *CNIConfig {
return &CNIConfig{
- Path: path,
- exec: exec,
+ Path: path,
+ cacheDir: cacheDir,
+ exec: exec,
}
}
@@ -165,33 +182,122 @@ func (c *CNIConfig) ensureExec() invoke.Exec {
return c.exec
}
-func getResultCacheFilePath(netName string, rt *RuntimeConf) string {
- cacheDir := rt.CacheDir
- if cacheDir == "" {
- cacheDir = CacheDir
+type cachedInfo struct {
+ Kind string `json:"kind"`
+ ContainerID string `json:"containerId"`
+ Config []byte `json:"config"`
+ IfName string `json:"ifName"`
+ NetworkName string `json:"networkName"`
+ CniArgs [][2]string `json:"cniArgs,omitempty"`
+ CapabilityArgs map[string]interface{} `json:"capabilityArgs,omitempty"`
+ RawResult map[string]interface{} `json:"result,omitempty"`
+ Result types.Result `json:"-"`
+}
+
+// getCacheDir returns the cache directory in this order:
+// 1) global cacheDir from CNIConfig object
+// 2) deprecated cacheDir from RuntimeConf object
+// 3) fall back to default cache directory
+func (c *CNIConfig) getCacheDir(rt *RuntimeConf) string {
+ if c.cacheDir != "" {
+ return c.cacheDir
+ }
+ if rt.CacheDir != "" {
+ return rt.CacheDir
+ }
+ return CacheDir
+}
+
+func (c *CNIConfig) getCacheFilePath(netName string, rt *RuntimeConf) (string, error) {
+ if netName == "" || rt.ContainerID == "" || rt.IfName == "" {
+ return "", fmt.Errorf("cache file path requires network name (%q), container ID (%q), and interface name (%q)", netName, rt.ContainerID, rt.IfName)
}
- return filepath.Join(cacheDir, "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName))
+ return filepath.Join(c.getCacheDir(rt), "results", fmt.Sprintf("%s-%s-%s", netName, rt.ContainerID, rt.IfName)), nil
}
-func setCachedResult(result types.Result, netName string, rt *RuntimeConf) error {
+func (c *CNIConfig) cacheAdd(result types.Result, config []byte, netName string, rt *RuntimeConf) error {
+ cached := cachedInfo{
+ Kind: CNICacheV1,
+ ContainerID: rt.ContainerID,
+ Config: config,
+ IfName: rt.IfName,
+ NetworkName: netName,
+ CniArgs: rt.Args,
+ CapabilityArgs: rt.CapabilityArgs,
+ }
+
+ // We need to get type.Result into cachedInfo as JSON map
+ // Marshal to []byte, then Unmarshal into cached.RawResult
data, err := json.Marshal(result)
if err != nil {
return err
}
- fname := getResultCacheFilePath(netName, rt)
+
+ err = json.Unmarshal(data, &cached.RawResult)
+ if err != nil {
+ return err
+ }
+
+ newBytes, err := json.Marshal(&cached)
+ if err != nil {
+ return err
+ }
+
+ fname, err := c.getCacheFilePath(netName, rt)
+ if err != nil {
+ return err
+ }
if err := os.MkdirAll(filepath.Dir(fname), 0700); err != nil {
return err
}
- return ioutil.WriteFile(fname, data, 0600)
+
+ return ioutil.WriteFile(fname, newBytes, 0600)
}
-func delCachedResult(netName string, rt *RuntimeConf) error {
- fname := getResultCacheFilePath(netName, rt)
+func (c *CNIConfig) cacheDel(netName string, rt *RuntimeConf) error {
+ fname, err := c.getCacheFilePath(netName, rt)
+ if err != nil {
+ // Ignore error
+ return nil
+ }
return os.Remove(fname)
}
-func getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
- fname := getResultCacheFilePath(netName, rt)
+func (c *CNIConfig) getCachedConfig(netName string, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
+ var bytes []byte
+
+ fname, err := c.getCacheFilePath(netName, rt)
+ if err != nil {
+ return nil, nil, err
+ }
+ bytes, err = ioutil.ReadFile(fname)
+ if err != nil {
+ // Ignore read errors; the cached result may not exist on-disk
+ return nil, nil, nil
+ }
+
+ unmarshaled := cachedInfo{}
+ if err := json.Unmarshal(bytes, &unmarshaled); err != nil {
+ return nil, nil, fmt.Errorf("failed to unmarshal cached network %q config: %v", netName, err)
+ }
+ if unmarshaled.Kind != CNICacheV1 {
+ return nil, nil, fmt.Errorf("read cached network %q config has wrong kind: %v", netName, unmarshaled.Kind)
+ }
+
+ newRt := *rt
+ if unmarshaled.CniArgs != nil {
+ newRt.Args = unmarshaled.CniArgs
+ }
+ newRt.CapabilityArgs = unmarshaled.CapabilityArgs
+
+ return unmarshaled.Config, &newRt, nil
+}
+
+func (c *CNIConfig) getLegacyCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
+ fname, err := c.getCacheFilePath(netName, rt)
+ if err != nil {
+ return nil, err
+ }
data, err := ioutil.ReadFile(fname)
if err != nil {
// Ignore read errors; the cached result may not exist on-disk
@@ -222,16 +328,73 @@ func getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result,
return result, err
}
+func (c *CNIConfig) getCachedResult(netName, cniVersion string, rt *RuntimeConf) (types.Result, error) {
+ fname, err := c.getCacheFilePath(netName, rt)
+ if err != nil {
+ return nil, err
+ }
+ fdata, err := ioutil.ReadFile(fname)
+ if err != nil {
+ // Ignore read errors; the cached result may not exist on-disk
+ return nil, nil
+ }
+
+ cachedInfo := cachedInfo{}
+ if err := json.Unmarshal(fdata, &cachedInfo); err != nil || cachedInfo.Kind != CNICacheV1 {
+ return c.getLegacyCachedResult(netName, cniVersion, rt)
+ }
+
+ newBytes, err := json.Marshal(&cachedInfo.RawResult)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal cached network %q config: %v", netName, err)
+ }
+
+ // Read the version of the cached result
+ decoder := version.ConfigDecoder{}
+ resultCniVersion, err := decoder.Decode(newBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Ensure we can understand the result
+ result, err := version.NewResult(resultCniVersion, newBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Convert to the config version to ensure plugins get prevResult
+ // in the same version as the config. The cached result version
+ // should match the config version unless the config was changed
+ // while the container was running.
+ result, err = result.GetAsVersion(cniVersion)
+ if err != nil && resultCniVersion != cniVersion {
+ return nil, fmt.Errorf("failed to convert cached result version %q to config version %q: %v", resultCniVersion, cniVersion, err)
+ }
+ return result, err
+}
+
// GetNetworkListCachedResult returns the cached Result of the previous
-// previous AddNetworkList() operation for a network list, or an error.
+// AddNetworkList() operation for a network list, or an error.
func (c *CNIConfig) GetNetworkListCachedResult(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
- return getCachedResult(list.Name, list.CNIVersion, rt)
+ return c.getCachedResult(list.Name, list.CNIVersion, rt)
}
// GetNetworkCachedResult returns the cached Result of the previous
-// previous AddNetwork() operation for a network, or an error.
+// AddNetwork() operation for a network, or an error.
func (c *CNIConfig) GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
- return getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
+ return c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
+}
+
+// GetNetworkListCachedConfig copies the input RuntimeConf to output
+// RuntimeConf with fields updated with info from the cached Config.
+func (c *CNIConfig) GetNetworkListCachedConfig(list *NetworkConfigList, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
+ return c.getCachedConfig(list.Name, rt)
+}
+
+// GetNetworkCachedConfig copies the input RuntimeConf to output
+// RuntimeConf with fields updated with info from the cached Config.
+func (c *CNIConfig) GetNetworkCachedConfig(net *NetworkConfig, rt *RuntimeConf) ([]byte, *RuntimeConf, error) {
+ return c.getCachedConfig(net.Network.Name, rt)
}
func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
@@ -240,6 +403,12 @@ func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net
if err != nil {
return nil, err
}
+ if err := utils.ValidateContainerID(rt.ContainerID); err != nil {
+ return nil, err
+ }
+ if err := utils.ValidateNetworkName(name); err != nil {
+ return nil, err
+ }
newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
if err != nil {
@@ -260,7 +429,7 @@ func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList,
}
}
- if err = setCachedResult(result, list.Name, rt); err != nil {
+ if err = c.cacheAdd(result, list.Bytes, list.Name, rt); err != nil {
return nil, fmt.Errorf("failed to set network %q cached result: %v", list.Name, err)
}
@@ -295,7 +464,7 @@ func (c *CNIConfig) CheckNetworkList(ctx context.Context, list *NetworkConfigLis
return nil
}
- cachedResult, err := getCachedResult(list.Name, list.CNIVersion, rt)
+ cachedResult, err := c.getCachedResult(list.Name, list.CNIVersion, rt)
if err != nil {
return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
}
@@ -332,7 +501,7 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
return err
} else if gtet {
- cachedResult, err = getCachedResult(list.Name, list.CNIVersion, rt)
+ cachedResult, err = c.getCachedResult(list.Name, list.CNIVersion, rt)
if err != nil {
return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
}
@@ -344,7 +513,7 @@ func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList,
return err
}
}
- _ = delCachedResult(list.Name, rt)
+ _ = c.cacheDel(list.Name, rt)
return nil
}
@@ -356,7 +525,7 @@ func (c *CNIConfig) AddNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
return nil, err
}
- if err = setCachedResult(result, net.Network.Name, rt); err != nil {
+ if err = c.cacheAdd(result, net.Bytes, net.Network.Name, rt); err != nil {
return nil, fmt.Errorf("failed to set network %q cached result: %v", net.Network.Name, err)
}
@@ -372,7 +541,7 @@ func (c *CNIConfig) CheckNetwork(ctx context.Context, net *NetworkConfig, rt *Ru
return fmt.Errorf("configuration version %q does not support the CHECK command", net.Network.CNIVersion)
}
- cachedResult, err := getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
+ cachedResult, err := c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
if err != nil {
return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err)
}
@@ -387,7 +556,7 @@ func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
if gtet, err := version.GreaterThanOrEqualTo(net.Network.CNIVersion, "0.4.0"); err != nil {
return err
} else if gtet {
- cachedResult, err = getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
+ cachedResult, err = c.getCachedResult(net.Network.Name, net.Network.CNIVersion, rt)
if err != nil {
return fmt.Errorf("failed to get network %q cached result: %v", net.Network.Name, err)
}
@@ -396,7 +565,7 @@ func (c *CNIConfig) DelNetwork(ctx context.Context, net *NetworkConfig, rt *Runt
if err := c.delNetwork(ctx, net.Network.Name, net.Network.CNIVersion, net, cachedResult, rt); err != nil {
return err
}
- _ = delCachedResult(net.Network.Name, rt)
+ _ = c.cacheDel(net.Network.Name, rt)
return nil
}
@@ -455,7 +624,8 @@ func (c *CNIConfig) ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]
// validatePlugin checks that an individual plugin's configuration is sane
func (c *CNIConfig) validatePlugin(ctx context.Context, pluginName, expectedVersion string) error {
- pluginPath, err := invoke.FindInPath(pluginName, c.Path)
+ c.ensureExec()
+ pluginPath, err := c.exec.FindInPath(pluginName, c.Path)
if err != nil {
return err
}
diff --git a/vendor/github.com/containernetworking/cni/libcni/conf.go b/vendor/github.com/containernetworking/cni/libcni/conf.go
index ea56c509d..d8920cf8c 100644
--- a/vendor/github.com/containernetworking/cni/libcni/conf.go
+++ b/vendor/github.com/containernetworking/cni/libcni/conf.go
@@ -114,11 +114,11 @@ func ConfListFromBytes(bytes []byte) (*NetworkConfigList, error) {
for i, conf := range plugins {
newBytes, err := json.Marshal(conf)
if err != nil {
- return nil, fmt.Errorf("Failed to marshal plugin config %d: %v", i, err)
+ return nil, fmt.Errorf("failed to marshal plugin config %d: %v", i, err)
}
netConf, err := ConfFromBytes(newBytes)
if err != nil {
- return nil, fmt.Errorf("Failed to parse plugin config %d: %v", i, err)
+ return nil, fmt.Errorf("failed to parse plugin config %d: %v", i, err)
}
list.Plugins = append(list.Plugins, netConf)
}
diff --git a/vendor/github.com/containernetworking/cni/pkg/invoke/args.go b/vendor/github.com/containernetworking/cni/pkg/invoke/args.go
index 913528c1d..d31a44e87 100644
--- a/vendor/github.com/containernetworking/cni/pkg/invoke/args.go
+++ b/vendor/github.com/containernetworking/cni/pkg/invoke/args.go
@@ -32,7 +32,7 @@ type inherited struct{}
var inheritArgsFromEnv inherited
-func (_ *inherited) AsEnv() []string {
+func (*inherited) AsEnv() []string {
return nil
}
diff --git a/vendor/github.com/containernetworking/cni/pkg/types/args.go b/vendor/github.com/containernetworking/cni/pkg/types/args.go
index bd8640fc9..4eac64899 100644
--- a/vendor/github.com/containernetworking/cni/pkg/types/args.go
+++ b/vendor/github.com/containernetworking/cni/pkg/types/args.go
@@ -36,7 +36,7 @@ func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
case "0", "false":
*b = false
default:
- return fmt.Errorf("Boolean unmarshal error: invalid input %s", s)
+ return fmt.Errorf("boolean unmarshal error: invalid input %s", s)
}
return nil
}
diff --git a/vendor/github.com/containernetworking/cni/pkg/types/types.go b/vendor/github.com/containernetworking/cni/pkg/types/types.go
index d0d11006a..3e185c1ce 100644
--- a/vendor/github.com/containernetworking/cni/pkg/types/types.go
+++ b/vendor/github.com/containernetworking/cni/pkg/types/types.go
@@ -16,7 +16,6 @@ package types
import (
"encoding/json"
- "errors"
"fmt"
"io"
"net"
@@ -134,9 +133,16 @@ func (r *Route) String() string {
// Well known error codes
// see https://github.com/containernetworking/cni/blob/master/SPEC.md#well-known-error-codes
const (
- ErrUnknown uint = iota // 0
- ErrIncompatibleCNIVersion // 1
- ErrUnsupportedField // 2
+ ErrUnknown uint = iota // 0
+ ErrIncompatibleCNIVersion // 1
+ ErrUnsupportedField // 2
+ ErrUnknownContainer // 3
+ ErrInvalidEnvironmentVariables // 4
+ ErrIOFailure // 5
+ ErrDecodingFailure // 6
+ ErrInvalidNetworkConfig // 7
+ ErrTryAgainLater uint = 11
+ ErrInternal uint = 999
)
type Error struct {
@@ -145,6 +151,14 @@ type Error struct {
Details string `json:"details,omitempty"`
}
+func NewError(code uint, msg, details string) *Error {
+ return &Error{
+ Code: code,
+ Msg: msg,
+ Details: details,
+ }
+}
+
func (e *Error) Error() string {
details := ""
if e.Details != "" {
@@ -194,6 +208,3 @@ func prettyPrint(obj interface{}) error {
_, err = os.Stdout.Write(data)
return err
}
-
-// NotImplementedError is used to indicate that a method is not implemented for the given platform
-var NotImplementedError = errors.New("Not Implemented")
diff --git a/vendor/github.com/containernetworking/cni/pkg/utils/utils.go b/vendor/github.com/containernetworking/cni/pkg/utils/utils.go
new file mode 100644
index 000000000..324c40dea
--- /dev/null
+++ b/vendor/github.com/containernetworking/cni/pkg/utils/utils.go
@@ -0,0 +1,51 @@
+// Copyright 2019 CNI authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package utils
+
+import (
+ "regexp"
+
+ "github.com/containernetworking/cni/pkg/types"
+)
+
+// cniValidNameChars is the regexp used to validate valid characters in
+// containerID and networkName
+const cniValidNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.\-]`
+
+var cniReg = regexp.MustCompile(`^` + cniValidNameChars + `*$`)
+
+// ValidateContainerID will validate that the supplied containerID is not empty does not contain invalid characters
+func ValidateContainerID(containerID string) *types.Error {
+
+ if containerID == "" {
+ return types.NewError(types.ErrUnknownContainer, "missing containerID", "")
+ }
+ if !cniReg.MatchString(containerID) {
+ return types.NewError(types.ErrInvalidEnvironmentVariables, "invalid characters in containerID", containerID)
+ }
+ return nil
+}
+
+// ValidateNetworkName will validate that the supplied networkName does not contain invalid characters
+func ValidateNetworkName(networkName string) *types.Error {
+
+ if networkName == "" {
+ return types.NewError(types.ErrInvalidNetworkConfig, "missing network name:", "")
+ }
+ if !cniReg.MatchString(networkName) {
+ return types.NewError(types.ErrInvalidNetworkConfig, "invalid characters found in network name", networkName)
+ }
+ return nil
+}
diff --git a/vendor/github.com/containers/storage/pkg/archive/example_changes.go b/vendor/github.com/containers/storage/pkg/archive/example_changes.go
deleted file mode 100644
index 70f9c5564..000000000
--- a/vendor/github.com/containers/storage/pkg/archive/example_changes.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// +build ignore
-
-// Simple tool to create an archive stream from an old and new directory
-//
-// By default it will stream the comparison of two temporary directories with junk files
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path"
-
- "github.com/containers/storage/pkg/archive"
- "github.com/sirupsen/logrus"
-)
-
-var (
- flDebug = flag.Bool("D", false, "debugging output")
- flNewDir = flag.String("newdir", "", "")
- flOldDir = flag.String("olddir", "", "")
- log = logrus.New()
-)
-
-func main() {
- flag.Usage = func() {
- fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)")
- fmt.Printf("%s [OPTIONS]\n", os.Args[0])
- flag.PrintDefaults()
- }
- flag.Parse()
- log.Out = os.Stderr
- if (len(os.Getenv("DEBUG")) > 0) || *flDebug {
- logrus.SetLevel(logrus.DebugLevel)
- }
- var newDir, oldDir string
-
- if len(*flNewDir) == 0 {
- var err error
- newDir, err = ioutil.TempDir("", "storage-test-newDir")
- if err != nil {
- log.Fatal(err)
- }
- defer os.RemoveAll(newDir)
- if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil {
- log.Fatal(err)
- }
- } else {
- newDir = *flNewDir
- }
-
- if len(*flOldDir) == 0 {
- oldDir, err := ioutil.TempDir("", "storage-test-oldDir")
- if err != nil {
- log.Fatal(err)
- }
- defer os.RemoveAll(oldDir)
- } else {
- oldDir = *flOldDir
- }
-
- changes, err := archive.ChangesDirs(newDir, oldDir)
- if err != nil {
- log.Fatal(err)
- }
-
- a, err := archive.ExportChanges(newDir, changes)
- if err != nil {
- log.Fatal(err)
- }
- defer a.Close()
-
- i, err := io.Copy(os.Stdout, a)
- if err != nil && err != io.EOF {
- log.Fatal(err)
- }
- fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i)
-}
-
-func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
- fileData := []byte("fooo")
- for n := 0; n < numberOfFiles; n++ {
- fileName := fmt.Sprintf("file-%d", n)
- if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
- return 0, err
- }
- if makeLinks {
- if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
- return 0, err
- }
- }
- }
- totalSize := numberOfFiles * len(fileData)
- return totalSize, nil
-}
diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
index 8743abc56..0cdbf14b7 100644
--- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
+++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go
@@ -2,11 +2,14 @@ package ocicni
import (
"context"
+ "encoding/json"
"errors"
"fmt"
+ "io/ioutil"
"net"
"os"
"path"
+ "path/filepath"
"sort"
"strings"
"sync"
@@ -21,10 +24,11 @@ import (
)
type cniNetworkPlugin struct {
+ cniConfig *libcni.CNIConfig
loNetwork *cniNetwork
sync.RWMutex
- defaultNetName string
+ defaultNetName netName
networks map[string]*cniNetwork
nsManager *nsManager
@@ -47,11 +51,15 @@ type cniNetworkPlugin struct {
cacheDir string
}
+type netName struct {
+ name string
+ changeable bool
+}
+
type cniNetwork struct {
- name string
- filePath string
- NetworkConfig *libcni.NetworkConfigList
- CNIConfig *libcni.CNIConfig
+ name string
+ filePath string
+ config *libcni.NetworkConfigList
}
var errMissingDefaultNetwork = errors.New("Missing CNI default network")
@@ -186,6 +194,8 @@ func (plugin *cniNetworkPlugin) monitorConfDir(start *sync.WaitGroup) {
// If defaultNetName is not empty, a CNI config with that network name will
// be used as the default CNI network, and container network operations will
// fail until that network config is present and valid.
+// If defaultNetName is empty, CNI config files should be reloaded real-time and
+// defaultNetName should be changeable and determined by file sorting.
func InitCNI(defaultNetName string, confDir string, binDirs ...string) (CNIPlugin, error) {
return initCNI(nil, "", defaultNetName, confDir, binDirs...)
}
@@ -198,17 +208,24 @@ func initCNI(exec cniinvoke.Exec, cacheDir, defaultNetName string, confDir strin
if len(binDirs) == 0 {
binDirs = []string{DefaultBinDir}
}
+
plugin := &cniNetworkPlugin{
- defaultNetName: defaultNetName,
- networks: make(map[string]*cniNetwork),
- loNetwork: getLoNetwork(exec, binDirs),
- confDir: confDir,
- binDirs: binDirs,
- shutdownChan: make(chan struct{}),
- done: &sync.WaitGroup{},
- pods: make(map[string]*podLock),
- exec: exec,
- cacheDir: cacheDir,
+ cniConfig: libcni.NewCNIConfig(binDirs, exec),
+ defaultNetName: netName{
+ name: defaultNetName,
+ // If defaultNetName is not assigned in initialization,
+ // it should be changeable
+ changeable: defaultNetName == "",
+ },
+ networks: make(map[string]*cniNetwork),
+ loNetwork: getLoNetwork(),
+ confDir: confDir,
+ binDirs: binDirs,
+ shutdownChan: make(chan struct{}),
+ done: &sync.WaitGroup{},
+ pods: make(map[string]*podLock),
+ exec: exec,
+ cacheDir: cacheDir,
}
if exec == nil {
@@ -246,7 +263,7 @@ func (plugin *cniNetworkPlugin) Shutdown() error {
return nil
}
-func loadNetworks(exec cniinvoke.Exec, confDir string, binDirs []string) (map[string]*cniNetwork, string, error) {
+func loadNetworks(confDir string, cni *libcni.CNIConfig) (map[string]*cniNetwork, string, error) {
files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"})
if err != nil {
return nil, "", err
@@ -284,17 +301,30 @@ func loadNetworks(exec cniinvoke.Exec, confDir string, binDirs []string) (map[st
logrus.Warningf("CNI config list %s has no networks, skipping", confFile)
continue
}
+
+ // Validation on CNI config should be done to pre-check presence
+ // of plugins which are necessary.
+ if _, err := cni.ValidateNetworkList(context.TODO(), confList); err != nil {
+ logrus.Warningf("Error validating CNI config file %s: %v", confFile, err)
+ continue
+ }
+
if confList.Name == "" {
confList.Name = path.Base(confFile)
}
+ cniNet := &cniNetwork{
+ name: confList.Name,
+ filePath: confFile,
+ config: confList,
+ }
+
logrus.Infof("Found CNI network %s (type=%v) at %s", confList.Name, confList.Plugins[0].Network.Type, confFile)
- networks[confList.Name] = &cniNetwork{
- name: confList.Name,
- filePath: confFile,
- NetworkConfig: confList,
- CNIConfig: libcni.NewCNIConfig(binDirs, exec),
+ if _, ok := networks[confList.Name]; !ok {
+ networks[confList.Name] = cniNet
+ } else {
+ logrus.Infof("Ignore CNI network %s (type=%v) at %s because already exists", confList.Name, confList.Plugins[0].Network.Type, confFile)
}
if defaultNetName == "" {
@@ -305,39 +335,49 @@ func loadNetworks(exec cniinvoke.Exec, confDir string, binDirs []string) (map[st
return networks, defaultNetName, nil
}
-func getLoNetwork(exec cniinvoke.Exec, binDirs []string) *cniNetwork {
- loConfig, err := libcni.ConfListFromBytes([]byte(`{
- "cniVersion": "0.2.0",
- "name": "cni-loopback",
+const (
+ loIfname string = "lo"
+ loNetname string = "cni-loopback"
+)
+
+func getLoNetwork() *cniNetwork {
+ loConfig, err := libcni.ConfListFromBytes([]byte(fmt.Sprintf(`{
+ "cniVersion": "0.3.1",
+ "name": "%s",
"plugins": [{
"type": "loopback"
}]
-}`))
+}`, loNetname)))
if err != nil {
// The hardcoded config above should always be valid and unit tests will
// catch this
panic(err)
}
loNetwork := &cniNetwork{
- name: "lo",
- NetworkConfig: loConfig,
- CNIConfig: libcni.NewCNIConfig(binDirs, exec),
+ name: loIfname,
+ config: loConfig,
}
return loNetwork
}
func (plugin *cniNetworkPlugin) syncNetworkConfig() error {
- networks, defaultNetName, err := loadNetworks(plugin.exec, plugin.confDir, plugin.binDirs)
+ networks, defaultNetName, err := loadNetworks(plugin.confDir, plugin.cniConfig)
if err != nil {
return err
}
plugin.Lock()
defer plugin.Unlock()
- if plugin.defaultNetName == "" {
- plugin.defaultNetName = defaultNetName
+
+ // Update defaultNetName if it is changeable
+ if plugin.defaultNetName.changeable {
+ plugin.defaultNetName.name = defaultNetName
+ logrus.Infof("Update default CNI network name to %s", defaultNetName)
+ } else {
+ logrus.Warnf("Default CNI network name %s is unchangeable", plugin.defaultNetName.name)
}
+
plugin.networks = networks
return nil
@@ -356,7 +396,7 @@ func (plugin *cniNetworkPlugin) getNetwork(name string) (*cniNetwork, error) {
func (plugin *cniNetworkPlugin) GetDefaultNetworkName() string {
plugin.RLock()
defer plugin.RUnlock()
- return plugin.defaultNetName
+ return plugin.defaultNetName.name
}
func (plugin *cniNetworkPlugin) getDefaultNetwork() *cniNetwork {
@@ -382,27 +422,120 @@ func (plugin *cniNetworkPlugin) Name() string {
return CNIPluginName
}
-func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, forEachFunc func(*cniNetwork, string, *PodNetwork, RuntimeConfig) error) error {
+func (plugin *cniNetworkPlugin) loadNetworkFromCache(name string, rt *libcni.RuntimeConf) (*cniNetwork, *libcni.RuntimeConf, error) {
+ cniNet := &cniNetwork{
+ name: name,
+ config: &libcni.NetworkConfigList{
+ Name: name,
+ },
+ }
+
+ var confBytes []byte
+ var err error
+ confBytes, rt, err = plugin.cniConfig.GetNetworkListCachedConfig(cniNet.config, rt)
+ if err != nil {
+ return nil, nil, err
+ } else if confBytes == nil {
+ return nil, nil, fmt.Errorf("network %q not found in CNI cache", name)
+ }
+
+ cniNet.config, err = libcni.ConfListFromBytes(confBytes)
+ if err != nil {
+ // Might be a plain NetworkConfig
+ netConf, err := libcni.ConfFromBytes(confBytes)
+ if err != nil {
+ return nil, nil, err
+ }
+ // Up-convert to a NetworkConfigList
+ cniNet.config, err = libcni.ConfListFromConf(netConf)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ return cniNet, rt, nil
+}
+
+type forEachNetworkFn func(*cniNetwork, *PodNetwork, *libcni.RuntimeConf) error
+
+func (plugin *cniNetworkPlugin) forEachNetwork(podNetwork *PodNetwork, fromCache bool, actionFn forEachNetworkFn) error {
networks := podNetwork.Networks
if len(networks) == 0 {
- networks = append(networks, plugin.GetDefaultNetworkName())
+ networks = append(networks, NetAttachment{
+ Name: plugin.GetDefaultNetworkName(),
+ })
}
- for i, netName := range networks {
- // Interface names start at "eth0" and count up for each network
- ifName := fmt.Sprintf("eth%d", i)
- network, err := plugin.getNetwork(netName)
+
+ allIfNames := make(map[string]bool)
+ for _, req := range networks {
+ if req.Ifname != "" {
+ // Make sure the requested name isn't already assigned
+ if allIfNames[req.Ifname] {
+ return fmt.Errorf("network %q requested interface name %q already assigned", req.Name, req.Ifname)
+ }
+ allIfNames[req.Ifname] = true
+ }
+ }
+
+ for _, network := range networks {
+ ifName := network.Ifname
+ if ifName == "" {
+ for i := 0; i < 10000; i++ {
+ candidate := fmt.Sprintf("eth%d", i)
+ if !allIfNames[candidate] {
+ allIfNames[candidate] = true
+ ifName = candidate
+ break
+ }
+ }
+ if ifName == "" {
+ return fmt.Errorf("failed to find free interface name for network %q", network.Name)
+ }
+ }
+
+ rt, err := buildCNIRuntimeConf(plugin.cacheDir, podNetwork, ifName, podNetwork.RuntimeConfig[network.Name])
if err != nil {
- logrus.Errorf(err.Error())
+ logrus.Errorf("error building CNI runtime config: %v", err)
return err
}
- if err := forEachFunc(network, ifName, podNetwork, podNetwork.RuntimeConfig[netName]); err != nil {
+
+ var cniNet *cniNetwork
+ if fromCache {
+ var newRt *libcni.RuntimeConf
+ cniNet, newRt, err = plugin.loadNetworkFromCache(network.Name, rt)
+ if err != nil {
+ logrus.Errorf("error loading cached network config: %v", err)
+ // fall back to loading from existing plugins on disk
+ } else {
+ // Use the updated RuntimeConf
+ rt = newRt
+ }
+ }
+ if cniNet == nil {
+ cniNet, err = plugin.getNetwork(network.Name)
+ if err != nil {
+ logrus.Errorf(err.Error())
+ return err
+ }
+ }
+
+ if err := actionFn(cniNet, podNetwork, rt); err != nil {
return err
}
}
return nil
}
-func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Result, error) {
+func buildLoopbackRuntimeConf(cacheDir string, podNetwork *PodNetwork) *libcni.RuntimeConf {
+ return &libcni.RuntimeConf{
+ ContainerID: podNetwork.ID,
+ NetNS: podNetwork.NetNS,
+ CacheDir: cacheDir,
+ IfName: loIfname,
+ }
+}
+
+func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]NetResult, error) {
if err := plugin.networksAvailable(&podNetwork); err != nil {
return nil, err
}
@@ -410,20 +543,26 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Resu
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
- _, err := plugin.loNetwork.addToNetwork(plugin.cacheDir, &podNetwork, "lo", RuntimeConfig{})
- if err != nil {
+ loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork)
+ if _, err := plugin.loNetwork.addToNetwork(loRt, plugin.cniConfig); err != nil {
logrus.Errorf("Error while adding to cni lo network: %s", err)
return nil, err
}
- results := make([]cnitypes.Result, 0)
- if err := plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork, runtimeConfig RuntimeConfig) error {
- result, err := network.addToNetwork(plugin.cacheDir, podNetwork, ifName, runtimeConfig)
+ results := make([]NetResult, 0)
+ if err := plugin.forEachNetwork(&podNetwork, false, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
+ result, err := network.addToNetwork(rt, plugin.cniConfig)
if err != nil {
logrus.Errorf("Error while adding pod to CNI network %q: %s", network.name, err)
return err
}
- results = append(results, result)
+ results = append(results, NetResult{
+ Result: result,
+ NetAttachment: NetAttachment{
+ Name: network.name,
+ Ifname: rt.IfName,
+ },
+ })
return nil
}); err != nil {
return nil, err
@@ -432,16 +571,99 @@ func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) ([]cnitypes.Resu
return results, nil
}
+func (plugin *cniNetworkPlugin) getCachedNetworkInfo(containerID string) ([]NetAttachment, error) {
+ cacheDir := libcni.CacheDir
+ if plugin.cacheDir != "" {
+ cacheDir = plugin.cacheDir
+ }
+
+ dirPath := filepath.Join(cacheDir, "results")
+ entries, err := ioutil.ReadDir(dirPath)
+ if err != nil {
+ return nil, err
+ }
+
+ fileNames := make([]string, 0, len(entries))
+ for _, e := range entries {
+ fileNames = append(fileNames, e.Name())
+ }
+ sort.Strings(fileNames)
+
+ attachments := []NetAttachment{}
+ for _, fname := range fileNames {
+ part := fmt.Sprintf("-%s-", containerID)
+ pos := strings.Index(fname, part)
+ if pos <= 0 || pos+len(part) >= len(fname) {
+ continue
+ }
+
+ cacheFile := filepath.Join(dirPath, fname)
+ bytes, err := ioutil.ReadFile(cacheFile)
+ if err != nil {
+ logrus.Warningf("failed to read CNI cache file %s: %v", cacheFile, err)
+ continue
+ }
+
+ cachedInfo := struct {
+ Kind string `json:"kind"`
+ IfName string `json:"ifName"`
+ ContainerID string `json:"containerID"`
+ NetName string `json:"networkName"`
+ }{}
+
+ if err := json.Unmarshal(bytes, &cachedInfo); err != nil {
+ logrus.Warningf("failed to unmarshal CNI cache file %s: %v", cacheFile, err)
+ continue
+ }
+ if cachedInfo.Kind != libcni.CNICacheV1 {
+ logrus.Warningf("unknown CNI cache file %s kind %q", cacheFile, cachedInfo.Kind)
+ continue
+ }
+ if cachedInfo.ContainerID != containerID {
+ continue
+ }
+ // Ignore the loopback interface; it's handled separately
+ if cachedInfo.IfName == loIfname && cachedInfo.NetName == loNetname {
+ continue
+ }
+ if cachedInfo.IfName == "" || cachedInfo.NetName == "" {
+ logrus.Warningf("missing CNI cache file %s ifname %q or netname %q", cacheFile, cachedInfo.IfName, cachedInfo.NetName)
+ continue
+ }
+
+ attachments = append(attachments, NetAttachment{
+ Name: cachedInfo.NetName,
+ Ifname: cachedInfo.IfName,
+ })
+ }
+ return attachments, nil
+}
+
+// TearDownPod tears down pod networks. Prefers cached pod attachment information
+// but falls back to given network attachment information.
func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
+ if len(podNetwork.Networks) == 0 {
+ attachments, err := plugin.getCachedNetworkInfo(podNetwork.ID)
+ if err == nil && len(attachments) > 0 {
+ podNetwork.Networks = attachments
+ }
+ }
+
if err := plugin.networksAvailable(&podNetwork); err != nil {
return err
}
+ loRt := buildLoopbackRuntimeConf(plugin.cacheDir, &podNetwork)
+ if err := plugin.loNetwork.deleteFromNetwork(loRt, plugin.cniConfig); err != nil {
+ logrus.Errorf("Error while removing pod from CNI lo network: %v", err)
+ // Loopback teardown errors are not fatal
+ }
+
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
- return plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork, runtimeConfig RuntimeConfig) error {
- if err := network.deleteFromNetwork(plugin.cacheDir, podNetwork, ifName, runtimeConfig); err != nil {
+ return plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
+ if err := network.deleteFromNetwork(rt, plugin.cniConfig); err != nil {
logrus.Errorf("Error while removing pod from CNI network %q: %s", network.name, err)
return err
}
@@ -451,19 +673,25 @@ func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error {
// GetPodNetworkStatus returns IP addressing and interface details for all
// networks attached to the pod.
-func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]cnitypes.Result, error) {
+func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]NetResult, error) {
plugin.podLock(podNetwork).Lock()
defer plugin.podUnlock(podNetwork)
- results := make([]cnitypes.Result, 0)
- if err := plugin.forEachNetwork(&podNetwork, func(network *cniNetwork, ifName string, podNetwork *PodNetwork, runtimeConfig RuntimeConfig) error {
- result, err := network.checkNetwork(plugin.cacheDir, podNetwork, ifName, runtimeConfig, plugin.nsManager)
+ results := make([]NetResult, 0)
+ if err := plugin.forEachNetwork(&podNetwork, true, func(network *cniNetwork, podNetwork *PodNetwork, rt *libcni.RuntimeConf) error {
+ result, err := network.checkNetwork(rt, plugin.cniConfig, plugin.nsManager, podNetwork.NetNS)
if err != nil {
logrus.Errorf("Error while checking pod to CNI network %q: %s", network.name, err)
return err
}
if result != nil {
- results = append(results, result)
+ results = append(results, NetResult{
+ Result: result,
+ NetAttachment: NetAttachment{
+ Name: network.name,
+ Ifname: rt.IfName,
+ },
+ })
}
return nil
}); err != nil {
@@ -473,16 +701,9 @@ func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) ([]cn
return results, nil
}
-func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig) (cnitypes.Result, error) {
- rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, runtimeConfig)
- if err != nil {
- logrus.Errorf("Error adding network: %v", err)
- return nil, err
- }
-
- netconf, cninet := network.NetworkConfig, network.CNIConfig
- logrus.Infof("About to add CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type)
- res, err := cninet.AddNetworkList(context.Background(), netconf, rt)
+func (network *cniNetwork) addToNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) (cnitypes.Result, error) {
+ logrus.Infof("About to add CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
+ res, err := cni.AddNetworkList(context.Background(), network.config, rt)
if err != nil {
logrus.Errorf("Error adding network: %v", err)
return nil, err
@@ -491,18 +712,10 @@ func (network *cniNetwork) addToNetwork(cacheDir string, podNetwork *PodNetwork,
return res, nil
}
-func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig, nsManager *nsManager) (cnitypes.Result, error) {
-
- rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, runtimeConfig)
- if err != nil {
- logrus.Errorf("Error checking network: %v", err)
- return nil, err
- }
-
- netconf, cninet := network.NetworkConfig, network.CNIConfig
- logrus.Infof("About to check CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type)
+func (network *cniNetwork) checkNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig, nsManager *nsManager, netns string) (cnitypes.Result, error) {
+ logrus.Infof("About to check CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
- gtet, err := cniversion.GreaterThanOrEqualTo(netconf.CNIVersion, "0.4.0")
+ gtet, err := cniversion.GreaterThanOrEqualTo(network.config.CNIVersion, "0.4.0")
if err != nil {
return nil, err
}
@@ -511,15 +724,15 @@ func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork,
// When CNIVersion supports Check, use it. Otherwise fall back on what was done initially.
if gtet {
- err = cninet.CheckNetworkList(context.Background(), netconf, rt)
- logrus.Infof("Checking CNI network %s (config version=%v)", netconf.Name, netconf.CNIVersion)
+ err = cni.CheckNetworkList(context.Background(), network.config, rt)
+ logrus.Infof("Checking CNI network %s (config version=%v)", network.name, network.config.CNIVersion)
if err != nil {
logrus.Errorf("Error checking network: %v", err)
return nil, err
}
}
- result, err = cninet.GetNetworkListCachedResult(netconf, rt)
+ result, err = cni.GetNetworkListCachedResult(network.config, rt)
if err != nil {
logrus.Errorf("Error GetNetworkListCachedResult: %v", err)
return nil, err
@@ -528,19 +741,19 @@ func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork,
}
// result doesn't exist, create one
- logrus.Infof("Checking CNI network %s (config version=%v) nsManager=%v", netconf.Name, netconf.CNIVersion, nsManager)
+ logrus.Infof("Checking CNI network %s (config version=%v) nsManager=%v", network.name, network.config.CNIVersion, nsManager)
var cniInterface *cnicurrent.Interface
ips := []*cnicurrent.IPConfig{}
errs := []error{}
for _, version := range []string{"4", "6"} {
- ip, mac, err := getContainerDetails(nsManager, podNetwork.NetNS, ifName, "-"+version)
+ ip, mac, err := getContainerDetails(nsManager, netns, rt.IfName, "-"+version)
if err == nil {
if cniInterface == nil {
cniInterface = &cnicurrent.Interface{
- Name: ifName,
+ Name: rt.IfName,
Mac: mac.String(),
- Sandbox: podNetwork.NetNS,
+ Sandbox: netns,
}
}
ips = append(ips, &cnicurrent.IPConfig{
@@ -557,25 +770,23 @@ func (network *cniNetwork) checkNetwork(cacheDir string, podNetwork *PodNetwork,
}
result = &cnicurrent.Result{
- CNIVersion: netconf.CNIVersion,
+ CNIVersion: network.config.CNIVersion,
Interfaces: []*cnicurrent.Interface{cniInterface},
IPs: ips,
}
- return result, nil
-}
-
-func (network *cniNetwork) deleteFromNetwork(cacheDir string, podNetwork *PodNetwork, ifName string, runtimeConfig RuntimeConfig) error {
- rt, err := buildCNIRuntimeConf(cacheDir, podNetwork, ifName, runtimeConfig)
+ // Result must be the same CNIVersion as the CNI config
+ converted, err := result.GetAsVersion(network.config.CNIVersion)
if err != nil {
- logrus.Errorf("Error deleting network: %v", err)
- return err
+ return nil, err
}
- netconf, cninet := network.NetworkConfig, network.CNIConfig
- logrus.Infof("About to del CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type)
- err = cninet.DelNetworkList(context.Background(), netconf, rt)
- if err != nil {
+ return converted, nil
+}
+
+func (network *cniNetwork) deleteFromNetwork(rt *libcni.RuntimeConf, cni *libcni.CNIConfig) error {
+ logrus.Infof("About to del CNI network %s (type=%v)", network.name, network.config.Plugins[0].Network.Type)
+ if err := cni.DelNetworkList(context.Background(), network.config, rt); err != nil {
logrus.Errorf("Error deleting network: %v", err)
return err
}
@@ -608,6 +819,16 @@ func buildCNIRuntimeConf(cacheDir string, podNetwork *PodNetwork, ifName string,
rt.Args = append(rt.Args, [2]string{"IP", ip})
}
+ // Add the requested static MAC to CNI_ARGS
+ mac := runtimeConfig.MAC
+ if mac != "" {
+ _, err := net.ParseMAC(mac)
+ if err != nil {
+ return nil, fmt.Errorf("unable to parse MAC address %q: %v", mac, err)
+ }
+ rt.Args = append(rt.Args, [2]string{"MAC", mac})
+ }
+
// Set PortMappings in Capabilities
if len(runtimeConfig.PortMappings) != 0 {
rt.CapabilityArgs["portMappings"] = runtimeConfig.PortMappings
diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
index 8709711e0..717ecda33 100644
--- a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
+++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go
@@ -44,6 +44,9 @@ type RuntimeConfig struct {
// with the hostlocal IP allocator. If left unset, an IP will be
// dynamically allocated.
IP string
+ // MAC is a static MAC address to be assigned to the network interface.
+ // If left unset, a MAC will be dynamically allocated.
+ MAC string
// PortMappings is the port mapping of the sandbox.
PortMappings []PortMapping
// Bandwidth is the bandwidth limiting of the pod
@@ -75,9 +78,10 @@ type PodNetwork struct {
// NetNS is the network namespace path of the sandbox.
NetNS string
- // Networks is a list of CNI network names to attach to the sandbox
- // Leave this list empty to attach the default network to the sandbox
- Networks []string
+ // Networks is a list of CNI network names (and optional interface
+ // names) to attach to the sandbox. Leave this list empty to attach the
+ // default network to the sandbox
+ Networks []NetAttachment
// NetworkConfig is configuration specific to a single CNI network.
// It is optional, and can be omitted for some or all specified networks
@@ -85,6 +89,24 @@ type PodNetwork struct {
RuntimeConfig map[string]RuntimeConfig
}
+// NetAttachment describes a container network attachment
+type NetAttachment struct {
+ // NetName contains the name of the CNI network to which the container
+ // should be or is attached
+ Name string
+ // Ifname contains the optional interface name of the attachment
+ Ifname string
+}
+
+// NetResult contains the result the network attachment operation
+type NetResult struct {
+ // Result is the CNI Result
+ Result types.Result
+ // NetAttachment contains the network and interface names of this
+ // network attachment
+ NetAttachment
+}
+
// CNIPlugin is the interface that needs to be implemented by a plugin
type CNIPlugin interface {
// Name returns the plugin's name. This will be used when searching
@@ -98,13 +120,13 @@ type CNIPlugin interface {
// SetUpPod is the method called after the sandbox container of
// the pod has been created but before the other containers of the
// pod are launched.
- SetUpPod(network PodNetwork) ([]types.Result, error)
+ SetUpPod(network PodNetwork) ([]NetResult, error)
// TearDownPod is the method called before a pod's sandbox container will be deleted
TearDownPod(network PodNetwork) error
// Status is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox
- GetPodNetworkStatus(network PodNetwork) ([]types.Result, error)
+ GetPodNetworkStatus(network PodNetwork) ([]NetResult, error)
// NetworkStatus returns error if the network plugin is in error state
Status() error
diff --git a/vendor/github.com/docker/docker/pkg/archive/example_changes.go b/vendor/github.com/docker/docker/pkg/archive/example_changes.go
deleted file mode 100644
index 495db809e..000000000
--- a/vendor/github.com/docker/docker/pkg/archive/example_changes.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// +build ignore
-
-// Simple tool to create an archive stream from an old and new directory
-//
-// By default it will stream the comparison of two temporary directories with junk files
-package main
-
-import (
- "flag"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path"
-
- "github.com/docker/docker/pkg/archive"
- "github.com/sirupsen/logrus"
-)
-
-var (
- flDebug = flag.Bool("D", false, "debugging output")
- flNewDir = flag.String("newdir", "", "")
- flOldDir = flag.String("olddir", "", "")
- log = logrus.New()
-)
-
-func main() {
- flag.Usage = func() {
- fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)")
- fmt.Printf("%s [OPTIONS]\n", os.Args[0])
- flag.PrintDefaults()
- }
- flag.Parse()
- log.Out = os.Stderr
- if (len(os.Getenv("DEBUG")) > 0) || *flDebug {
- logrus.SetLevel(logrus.DebugLevel)
- }
- var newDir, oldDir string
-
- if len(*flNewDir) == 0 {
- var err error
- newDir, err = ioutil.TempDir("", "docker-test-newDir")
- if err != nil {
- log.Fatal(err)
- }
- defer os.RemoveAll(newDir)
- if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil {
- log.Fatal(err)
- }
- } else {
- newDir = *flNewDir
- }
-
- if len(*flOldDir) == 0 {
- oldDir, err := ioutil.TempDir("", "docker-test-oldDir")
- if err != nil {
- log.Fatal(err)
- }
- defer os.RemoveAll(oldDir)
- } else {
- oldDir = *flOldDir
- }
-
- changes, err := archive.ChangesDirs(newDir, oldDir)
- if err != nil {
- log.Fatal(err)
- }
-
- a, err := archive.ExportChanges(newDir, changes)
- if err != nil {
- log.Fatal(err)
- }
- defer a.Close()
-
- i, err := io.Copy(os.Stdout, a)
- if err != nil && err != io.EOF {
- log.Fatal(err)
- }
- fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i)
-}
-
-func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
- fileData := []byte("fooo")
- for n := 0; n < numberOfFiles; n++ {
- fileName := fmt.Sprintf("file-%d", n)
- if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
- return 0, err
- }
- if makeLinks {
- if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
- return 0, err
- }
- }
- }
- totalSize := numberOfFiles * len(fileData)
- return totalSize, nil
-}
diff --git a/vendor/github.com/json-iterator/go/iter.go b/vendor/github.com/json-iterator/go/iter.go
index 95ae54fbf..29b31cf78 100644
--- a/vendor/github.com/json-iterator/go/iter.go
+++ b/vendor/github.com/json-iterator/go/iter.go
@@ -74,6 +74,7 @@ type Iterator struct {
buf []byte
head int
tail int
+ depth int
captureStartedAt int
captured []byte
Error error
@@ -88,6 +89,7 @@ func NewIterator(cfg API) *Iterator {
buf: nil,
head: 0,
tail: 0,
+ depth: 0,
}
}
@@ -99,6 +101,7 @@ func Parse(cfg API, reader io.Reader, bufSize int) *Iterator {
buf: make([]byte, bufSize),
head: 0,
tail: 0,
+ depth: 0,
}
}
@@ -110,6 +113,7 @@ func ParseBytes(cfg API, input []byte) *Iterator {
buf: input,
head: 0,
tail: len(input),
+ depth: 0,
}
}
@@ -128,6 +132,7 @@ func (iter *Iterator) Reset(reader io.Reader) *Iterator {
iter.reader = reader
iter.head = 0
iter.tail = 0
+ iter.depth = 0
return iter
}
@@ -137,6 +142,7 @@ func (iter *Iterator) ResetBytes(input []byte) *Iterator {
iter.buf = input
iter.head = 0
iter.tail = len(input)
+ iter.depth = 0
return iter
}
@@ -320,3 +326,24 @@ func (iter *Iterator) Read() interface{} {
return nil
}
}
+
+// limit maximum depth of nesting, as allowed by https://tools.ietf.org/html/rfc7159#section-9
+const maxDepth = 10000
+
+func (iter *Iterator) incrementDepth() (success bool) {
+ iter.depth++
+ if iter.depth <= maxDepth {
+ return true
+ }
+ iter.ReportError("incrementDepth", "exceeded max depth")
+ return false
+}
+
+func (iter *Iterator) decrementDepth() (success bool) {
+ iter.depth--
+ if iter.depth >= 0 {
+ return true
+ }
+ iter.ReportError("decrementDepth", "unexpected negative nesting")
+ return false
+}
diff --git a/vendor/github.com/json-iterator/go/iter_array.go b/vendor/github.com/json-iterator/go/iter_array.go
index 6188cb457..204fe0e09 100644
--- a/vendor/github.com/json-iterator/go/iter_array.go
+++ b/vendor/github.com/json-iterator/go/iter_array.go
@@ -28,26 +28,32 @@ func (iter *Iterator) ReadArray() (ret bool) {
func (iter *Iterator) ReadArrayCB(callback func(*Iterator) bool) (ret bool) {
c := iter.nextToken()
if c == '[' {
+ if !iter.incrementDepth() {
+ return false
+ }
c = iter.nextToken()
if c != ']' {
iter.unreadByte()
if !callback(iter) {
+ iter.decrementDepth()
return false
}
c = iter.nextToken()
for c == ',' {
if !callback(iter) {
+ iter.decrementDepth()
return false
}
c = iter.nextToken()
}
if c != ']' {
iter.ReportError("ReadArrayCB", "expect ] in the end, but found "+string([]byte{c}))
+ iter.decrementDepth()
return false
}
- return true
+ return iter.decrementDepth()
}
- return true
+ return iter.decrementDepth()
}
if c == 'n' {
iter.skipThreeBytes('u', 'l', 'l')
diff --git a/vendor/github.com/json-iterator/go/iter_object.go b/vendor/github.com/json-iterator/go/iter_object.go
index 1c5757671..b65137114 100644
--- a/vendor/github.com/json-iterator/go/iter_object.go
+++ b/vendor/github.com/json-iterator/go/iter_object.go
@@ -112,6 +112,9 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken()
var field string
if c == '{' {
+ if !iter.incrementDepth() {
+ return false
+ }
c = iter.nextToken()
if c == '"' {
iter.unreadByte()
@@ -121,6 +124,7 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
if !callback(iter, field) {
+ iter.decrementDepth()
return false
}
c = iter.nextToken()
@@ -131,20 +135,23 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
iter.ReportError("ReadObject", "expect : after object field, but found "+string([]byte{c}))
}
if !callback(iter, field) {
+ iter.decrementDepth()
return false
}
c = iter.nextToken()
}
if c != '}' {
iter.ReportError("ReadObjectCB", `object not ended with }`)
+ iter.decrementDepth()
return false
}
- return true
+ return iter.decrementDepth()
}
if c == '}' {
- return true
+ return iter.decrementDepth()
}
iter.ReportError("ReadObjectCB", `expect " after }, but found `+string([]byte{c}))
+ iter.decrementDepth()
return false
}
if c == 'n' {
@@ -159,15 +166,20 @@ func (iter *Iterator) ReadObjectCB(callback func(*Iterator, string) bool) bool {
func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
c := iter.nextToken()
if c == '{' {
+ if !iter.incrementDepth() {
+ return false
+ }
c = iter.nextToken()
if c == '"' {
iter.unreadByte()
field := iter.ReadString()
if iter.nextToken() != ':' {
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
+ iter.decrementDepth()
return false
}
if !callback(iter, field) {
+ iter.decrementDepth()
return false
}
c = iter.nextToken()
@@ -175,23 +187,27 @@ func (iter *Iterator) ReadMapCB(callback func(*Iterator, string) bool) bool {
field = iter.ReadString()
if iter.nextToken() != ':' {
iter.ReportError("ReadMapCB", "expect : after object field, but found "+string([]byte{c}))
+ iter.decrementDepth()
return false
}
if !callback(iter, field) {
+ iter.decrementDepth()
return false
}
c = iter.nextToken()
}
if c != '}' {
iter.ReportError("ReadMapCB", `object not ended with }`)
+ iter.decrementDepth()
return false
}
- return true
+ return iter.decrementDepth()
}
if c == '}' {
- return true
+ return iter.decrementDepth()
}
iter.ReportError("ReadMapCB", `expect " after }, but found `+string([]byte{c}))
+ iter.decrementDepth()
return false
}
if c == 'n' {
diff --git a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go
index 8fcdc3b69..9303de41e 100644
--- a/vendor/github.com/json-iterator/go/iter_skip_sloppy.go
+++ b/vendor/github.com/json-iterator/go/iter_skip_sloppy.go
@@ -22,6 +22,9 @@ func (iter *Iterator) skipNumber() {
func (iter *Iterator) skipArray() {
level := 1
+ if !iter.incrementDepth() {
+ return
+ }
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
@@ -31,8 +34,14 @@ func (iter *Iterator) skipArray() {
i = iter.head - 1 // it will be i++ soon
case '[': // If open symbol, increase level
level++
+ if !iter.incrementDepth() {
+ return
+ }
case ']': // If close symbol, increase level
level--
+ if !iter.decrementDepth() {
+ return
+ }
// If we have returned to the original level, we're done
if level == 0 {
@@ -50,6 +59,10 @@ func (iter *Iterator) skipArray() {
func (iter *Iterator) skipObject() {
level := 1
+ if !iter.incrementDepth() {
+ return
+ }
+
for {
for i := iter.head; i < iter.tail; i++ {
switch iter.buf[i] {
@@ -59,8 +72,14 @@ func (iter *Iterator) skipObject() {
i = iter.head - 1 // it will be i++ soon
case '{': // If open symbol, increase level
level++
+ if !iter.incrementDepth() {
+ return
+ }
case '}': // If close symbol, increase level
level--
+ if !iter.decrementDepth() {
+ return
+ }
// If we have returned to the original level, we're done
if level == 0 {
diff --git a/vendor/github.com/json-iterator/go/reflect.go b/vendor/github.com/json-iterator/go/reflect.go
index 4459e203f..74974ba74 100644
--- a/vendor/github.com/json-iterator/go/reflect.go
+++ b/vendor/github.com/json-iterator/go/reflect.go
@@ -60,6 +60,7 @@ func (b *ctx) append(prefix string) *ctx {
// ReadVal copy the underlying JSON into go interface, same as json.Unmarshal
func (iter *Iterator) ReadVal(obj interface{}) {
+ depth := iter.depth
cacheKey := reflect2.RTypeOf(obj)
decoder := iter.cfg.getDecoderFromCache(cacheKey)
if decoder == nil {
@@ -76,6 +77,10 @@ func (iter *Iterator) ReadVal(obj interface{}) {
return
}
decoder.Decode(ptr, iter)
+ if iter.depth != depth {
+ iter.ReportError("ReadVal", "unexpected mismatched nesting")
+ return
+ }
}
// WriteVal copy the go interface into underlying JSON, same as json.Marshal
diff --git a/vendor/github.com/json-iterator/go/reflect_extension.go b/vendor/github.com/json-iterator/go/reflect_extension.go
index 05e8fbf1f..e27e8d191 100644
--- a/vendor/github.com/json-iterator/go/reflect_extension.go
+++ b/vendor/github.com/json-iterator/go/reflect_extension.go
@@ -341,10 +341,10 @@ func describeStruct(ctx *ctx, typ reflect2.Type) *StructDescriptor {
if ctx.onlyTaggedField && !hastag && !field.Anonymous() {
continue
}
- tagParts := strings.Split(tag, ",")
if tag == "-" {
continue
}
+ tagParts := strings.Split(tag, ",")
if field.Anonymous() && (tag == "" || tagParts[0] == "") {
if field.Type().Kind() == reflect.Struct {
structDescriptor := describeStruct(ctx, field.Type())
diff --git a/vendor/github.com/json-iterator/go/reflect_map.go b/vendor/github.com/json-iterator/go/reflect_map.go
index 547b4421e..08e9a3912 100644
--- a/vendor/github.com/json-iterator/go/reflect_map.go
+++ b/vendor/github.com/json-iterator/go/reflect_map.go
@@ -249,6 +249,10 @@ type mapEncoder struct {
}
func (encoder *mapEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
+ if *(*unsafe.Pointer)(ptr) == nil {
+ stream.WriteNil()
+ return
+ }
stream.WriteObjectStart()
iter := encoder.mapType.UnsafeIterate(ptr)
for i := 0; iter.HasNext(); i++ {
diff --git a/vendor/github.com/json-iterator/go/reflect_marshaler.go b/vendor/github.com/json-iterator/go/reflect_marshaler.go
index fea50719d..3e21f3756 100644
--- a/vendor/github.com/json-iterator/go/reflect_marshaler.go
+++ b/vendor/github.com/json-iterator/go/reflect_marshaler.go
@@ -3,8 +3,9 @@ package jsoniter
import (
"encoding"
"encoding/json"
- "github.com/modern-go/reflect2"
"unsafe"
+
+ "github.com/modern-go/reflect2"
)
var marshalerType = reflect2.TypeOfPtr((*json.Marshaler)(nil)).Elem()
@@ -93,10 +94,17 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
stream.WriteNil()
return
}
- bytes, err := json.Marshal(obj)
+ marshaler := obj.(json.Marshaler)
+ bytes, err := marshaler.MarshalJSON()
if err != nil {
stream.Error = err
} else {
+ // html escape was already done by jsoniter
+ // but the extra '\n' should be trimed
+ l := len(bytes)
+ if l > 0 && bytes[l-1] == '\n' {
+ bytes = bytes[:l-1]
+ }
stream.Write(bytes)
}
}
diff --git a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go
index 932641ac4..5ad5cc561 100644
--- a/vendor/github.com/json-iterator/go/reflect_struct_decoder.go
+++ b/vendor/github.com/json-iterator/go/reflect_struct_decoder.go
@@ -500,6 +500,9 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
var c byte
for c = ','; c == ','; c = iter.nextToken() {
decoder.decodeOneField(ptr, iter)
@@ -510,6 +513,7 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
if c != '}' {
iter.ReportError("struct Decode", `expect }, but found `+string([]byte{c}))
}
+ iter.decrementDepth()
}
func (decoder *generalStructDecoder) decodeOneField(ptr unsafe.Pointer, iter *Iterator) {
@@ -571,6 +575,9 @@ func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
if iter.readFieldHash() == decoder.fieldHash {
decoder.fieldDecoder.Decode(ptr, iter)
@@ -584,6 +591,7 @@ func (decoder *oneFieldStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type twoFieldsStructDecoder struct {
@@ -598,6 +606,9 @@ func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -614,6 +625,7 @@ func (decoder *twoFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type threeFieldsStructDecoder struct {
@@ -630,6 +642,9 @@ func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -648,6 +663,7 @@ func (decoder *threeFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type fourFieldsStructDecoder struct {
@@ -666,6 +682,9 @@ func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -686,6 +705,7 @@ func (decoder *fourFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type fiveFieldsStructDecoder struct {
@@ -706,6 +726,9 @@ func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -728,6 +751,7 @@ func (decoder *fiveFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type sixFieldsStructDecoder struct {
@@ -750,6 +774,9 @@ func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -774,6 +801,7 @@ func (decoder *sixFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type sevenFieldsStructDecoder struct {
@@ -798,6 +826,9 @@ func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -824,6 +855,7 @@ func (decoder *sevenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type eightFieldsStructDecoder struct {
@@ -850,6 +882,9 @@ func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -878,6 +913,7 @@ func (decoder *eightFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterat
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type nineFieldsStructDecoder struct {
@@ -906,6 +942,9 @@ func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -936,6 +975,7 @@ func (decoder *nineFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterato
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type tenFieldsStructDecoder struct {
@@ -966,6 +1006,9 @@ func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
if !iter.readObjectStart() {
return
}
+ if !iter.incrementDepth() {
+ return
+ }
for {
switch iter.readFieldHash() {
case decoder.fieldHash1:
@@ -998,6 +1041,7 @@ func (decoder *tenFieldsStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator
if iter.Error != nil && iter.Error != io.EOF {
iter.Error = fmt.Errorf("%v.%s", decoder.typ, iter.Error.Error())
}
+ iter.decrementDepth()
}
type structFieldDecoder struct {
diff --git a/vendor/github.com/klauspost/compress/flate/gen.go b/vendor/github.com/klauspost/compress/flate/gen.go
deleted file mode 100644
index 154c89a48..000000000
--- a/vendor/github.com/klauspost/compress/flate/gen.go
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// This program generates fixedhuff.go
-// Invoke as
-//
-// go run gen.go -output fixedhuff.go
-
-package main
-
-import (
- "bytes"
- "flag"
- "fmt"
- "go/format"
- "io/ioutil"
- "log"
-)
-
-var filename = flag.String("output", "fixedhuff.go", "output file name")
-
-const maxCodeLen = 16
-
-// Note: the definition of the huffmanDecoder struct is copied from
-// inflate.go, as it is private to the implementation.
-
-// chunk & 15 is number of bits
-// chunk >> 4 is value, including table link
-
-const (
- huffmanChunkBits = 9
- huffmanNumChunks = 1 << huffmanChunkBits
- huffmanCountMask = 15
- huffmanValueShift = 4
-)
-
-type huffmanDecoder struct {
- min int // the minimum code length
- chunks [huffmanNumChunks]uint32 // chunks as described above
- links [][]uint32 // overflow links
- linkMask uint32 // mask the width of the link table
-}
-
-// Initialize Huffman decoding tables from array of code lengths.
-// Following this function, h is guaranteed to be initialized into a complete
-// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
-// degenerate case where the tree has only a single symbol with length 1. Empty
-// trees are permitted.
-func (h *huffmanDecoder) init(bits []int) bool {
- // Sanity enables additional runtime tests during Huffman
- // table construction. It's intended to be used during
- // development to supplement the currently ad-hoc unit tests.
- const sanity = false
-
- if h.min != 0 {
- *h = huffmanDecoder{}
- }
-
- // Count number of codes of each length,
- // compute min and max length.
- var count [maxCodeLen]int
- var min, max int
- for _, n := range bits {
- if n == 0 {
- continue
- }
- if min == 0 || n < min {
- min = n
- }
- if n > max {
- max = n
- }
- count[n]++
- }
-
- // Empty tree. The decompressor.huffSym function will fail later if the tree
- // is used. Technically, an empty tree is only valid for the HDIST tree and
- // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
- // is guaranteed to fail since it will attempt to use the tree to decode the
- // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
- // guaranteed to fail later since the compressed data section must be
- // composed of at least one symbol (the end-of-block marker).
- if max == 0 {
- return true
- }
-
- code := 0
- var nextcode [maxCodeLen]int
- for i := min; i <= max; i++ {
- code <<= 1
- nextcode[i] = code
- code += count[i]
- }
-
- // Check that the coding is complete (i.e., that we've
- // assigned all 2-to-the-max possible bit sequences).
- // Exception: To be compatible with zlib, we also need to
- // accept degenerate single-code codings. See also
- // TestDegenerateHuffmanCoding.
- if code != 1<<uint(max) && !(code == 1 && max == 1) {
- return false
- }
-
- h.min = min
- if max > huffmanChunkBits {
- numLinks := 1 << (uint(max) - huffmanChunkBits)
- h.linkMask = uint32(numLinks - 1)
-
- // create link tables
- link := nextcode[huffmanChunkBits+1] >> 1
- h.links = make([][]uint32, huffmanNumChunks-link)
- for j := uint(link); j < huffmanNumChunks; j++ {
- reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
- reverse >>= uint(16 - huffmanChunkBits)
- off := j - uint(link)
- if sanity && h.chunks[reverse] != 0 {
- panic("impossible: overwriting existing chunk")
- }
- h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
- h.links[off] = make([]uint32, numLinks)
- }
- }
-
- for i, n := range bits {
- if n == 0 {
- continue
- }
- code := nextcode[n]
- nextcode[n]++
- chunk := uint32(i<<huffmanValueShift | n)
- reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
- reverse >>= uint(16 - n)
- if n <= huffmanChunkBits {
- for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
- // We should never need to overwrite
- // an existing chunk. Also, 0 is
- // never a valid chunk, because the
- // lower 4 "count" bits should be
- // between 1 and 15.
- if sanity && h.chunks[off] != 0 {
- panic("impossible: overwriting existing chunk")
- }
- h.chunks[off] = chunk
- }
- } else {
- j := reverse & (huffmanNumChunks - 1)
- if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
- // Longer codes should have been
- // associated with a link table above.
- panic("impossible: not an indirect chunk")
- }
- value := h.chunks[j] >> huffmanValueShift
- linktab := h.links[value]
- reverse >>= huffmanChunkBits
- for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
- if sanity && linktab[off] != 0 {
- panic("impossible: overwriting existing chunk")
- }
- linktab[off] = chunk
- }
- }
- }
-
- if sanity {
- // Above we've sanity checked that we never overwrote
- // an existing entry. Here we additionally check that
- // we filled the tables completely.
- for i, chunk := range h.chunks {
- if chunk == 0 {
- // As an exception, in the degenerate
- // single-code case, we allow odd
- // chunks to be missing.
- if code == 1 && i%2 == 1 {
- continue
- }
- panic("impossible: missing chunk")
- }
- }
- for _, linktab := range h.links {
- for _, chunk := range linktab {
- if chunk == 0 {
- panic("impossible: missing chunk")
- }
- }
- }
- }
-
- return true
-}
-
-func main() {
- flag.Parse()
-
- var h huffmanDecoder
- var bits [288]int
- initReverseByte()
- for i := 0; i < 144; i++ {
- bits[i] = 8
- }
- for i := 144; i < 256; i++ {
- bits[i] = 9
- }
- for i := 256; i < 280; i++ {
- bits[i] = 7
- }
- for i := 280; i < 288; i++ {
- bits[i] = 8
- }
- h.init(bits[:])
- if h.links != nil {
- log.Fatal("Unexpected links table in fixed Huffman decoder")
- }
-
- var buf bytes.Buffer
-
- fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.`+"\n\n")
-
- fmt.Fprintln(&buf, "package flate")
- fmt.Fprintln(&buf)
- fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT")
- fmt.Fprintln(&buf)
- fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{")
- fmt.Fprintf(&buf, "\t%d,\n", h.min)
- fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{")
- for i := 0; i < huffmanNumChunks; i++ {
- if i&7 == 0 {
- fmt.Fprintf(&buf, "\t\t")
- } else {
- fmt.Fprintf(&buf, " ")
- }
- fmt.Fprintf(&buf, "0x%04x,", h.chunks[i])
- if i&7 == 7 {
- fmt.Fprintln(&buf)
- }
- }
- fmt.Fprintln(&buf, "\t},")
- fmt.Fprintln(&buf, "\tnil, 0,")
- fmt.Fprintln(&buf, "}")
-
- data, err := format.Source(buf.Bytes())
- if err != nil {
- log.Fatal(err)
- }
- err = ioutil.WriteFile(*filename, data, 0644)
- if err != nil {
- log.Fatal(err)
- }
-}
-
-var reverseByte [256]byte
-
-func initReverseByte() {
- for x := 0; x < 256; x++ {
- var result byte
- for i := uint(0); i < 8; i++ {
- result |= byte(((x >> i) & 1) << (7 - i))
- }
- reverseByte[x] = result
- }
-}
diff --git a/vendor/github.com/klauspost/cpuid/private-gen.go b/vendor/github.com/klauspost/cpuid/private-gen.go
deleted file mode 100644
index 437333d29..000000000
--- a/vendor/github.com/klauspost/cpuid/private-gen.go
+++ /dev/null
@@ -1,476 +0,0 @@
-// +build ignore
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/parser"
- "go/printer"
- "go/token"
- "io"
- "io/ioutil"
- "log"
- "os"
- "reflect"
- "strings"
- "unicode"
- "unicode/utf8"
-)
-
-var inFiles = []string{"cpuid.go", "cpuid_test.go"}
-var copyFiles = []string{"cpuid_amd64.s", "cpuid_386.s", "detect_ref.go", "detect_intel.go"}
-var fileSet = token.NewFileSet()
-var reWrites = []rewrite{
- initRewrite("CPUInfo -> cpuInfo"),
- initRewrite("Vendor -> vendor"),
- initRewrite("Flags -> flags"),
- initRewrite("Detect -> detect"),
- initRewrite("CPU -> cpu"),
-}
-var excludeNames = map[string]bool{"string": true, "join": true, "trim": true,
- // cpuid_test.go
- "t": true, "println": true, "logf": true, "log": true, "fatalf": true, "fatal": true,
-}
-
-var excludePrefixes = []string{"test", "benchmark"}
-
-func main() {
- Package := "private"
- parserMode := parser.ParseComments
- exported := make(map[string]rewrite)
- for _, file := range inFiles {
- in, err := os.Open(file)
- if err != nil {
- log.Fatalf("opening input", err)
- }
-
- src, err := ioutil.ReadAll(in)
- if err != nil {
- log.Fatalf("reading input", err)
- }
-
- astfile, err := parser.ParseFile(fileSet, file, src, parserMode)
- if err != nil {
- log.Fatalf("parsing input", err)
- }
-
- for _, rw := range reWrites {
- astfile = rw(astfile)
- }
-
- // Inspect the AST and print all identifiers and literals.
- var startDecl token.Pos
- var endDecl token.Pos
- ast.Inspect(astfile, func(n ast.Node) bool {
- var s string
- switch x := n.(type) {
- case *ast.Ident:
- if x.IsExported() {
- t := strings.ToLower(x.Name)
- for _, pre := range excludePrefixes {
- if strings.HasPrefix(t, pre) {
- return true
- }
- }
- if excludeNames[t] != true {
- //if x.Pos() > startDecl && x.Pos() < endDecl {
- exported[x.Name] = initRewrite(x.Name + " -> " + t)
- }
- }
-
- case *ast.GenDecl:
- if x.Tok == token.CONST && x.Lparen > 0 {
- startDecl = x.Lparen
- endDecl = x.Rparen
- // fmt.Printf("Decl:%s -> %s\n", fileSet.Position(startDecl), fileSet.Position(endDecl))
- }
- }
- if s != "" {
- fmt.Printf("%s:\t%s\n", fileSet.Position(n.Pos()), s)
- }
- return true
- })
-
- for _, rw := range exported {
- astfile = rw(astfile)
- }
-
- var buf bytes.Buffer
-
- printer.Fprint(&buf, fileSet, astfile)
-
- // Remove package documentation and insert information
- s := buf.String()
- ind := strings.Index(buf.String(), "\npackage cpuid")
- s = s[ind:]
- s = "// Generated, DO NOT EDIT,\n" +
- "// but copy it to your own project and rename the package.\n" +
- "// See more at http://github.com/klauspost/cpuid\n" +
- s
-
- outputName := Package + string(os.PathSeparator) + file
-
- err = ioutil.WriteFile(outputName, []byte(s), 0644)
- if err != nil {
- log.Fatalf("writing output: %s", err)
- }
- log.Println("Generated", outputName)
- }
-
- for _, file := range copyFiles {
- dst := ""
- if strings.HasPrefix(file, "cpuid") {
- dst = Package + string(os.PathSeparator) + file
- } else {
- dst = Package + string(os.PathSeparator) + "cpuid_" + file
- }
- err := copyFile(file, dst)
- if err != nil {
- log.Fatalf("copying file: %s", err)
- }
- log.Println("Copied", dst)
- }
-}
-
-// CopyFile copies a file from src to dst. If src and dst files exist, and are
-// the same, then return success. Copy the file contents from src to dst.
-func copyFile(src, dst string) (err error) {
- sfi, err := os.Stat(src)
- if err != nil {
- return
- }
- if !sfi.Mode().IsRegular() {
- // cannot copy non-regular files (e.g., directories,
- // symlinks, devices, etc.)
- return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
- }
- dfi, err := os.Stat(dst)
- if err != nil {
- if !os.IsNotExist(err) {
- return
- }
- } else {
- if !(dfi.Mode().IsRegular()) {
- return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
- }
- if os.SameFile(sfi, dfi) {
- return
- }
- }
- err = copyFileContents(src, dst)
- return
-}
-
-// copyFileContents copies the contents of the file named src to the file named
-// by dst. The file will be created if it does not already exist. If the
-// destination file exists, all it's contents will be replaced by the contents
-// of the source file.
-func copyFileContents(src, dst string) (err error) {
- in, err := os.Open(src)
- if err != nil {
- return
- }
- defer in.Close()
- out, err := os.Create(dst)
- if err != nil {
- return
- }
- defer func() {
- cerr := out.Close()
- if err == nil {
- err = cerr
- }
- }()
- if _, err = io.Copy(out, in); err != nil {
- return
- }
- err = out.Sync()
- return
-}
-
-type rewrite func(*ast.File) *ast.File
-
-// Mostly copied from gofmt
-func initRewrite(rewriteRule string) rewrite {
- f := strings.Split(rewriteRule, "->")
- if len(f) != 2 {
- fmt.Fprintf(os.Stderr, "rewrite rule must be of the form 'pattern -> replacement'\n")
- os.Exit(2)
- }
- pattern := parseExpr(f[0], "pattern")
- replace := parseExpr(f[1], "replacement")
- return func(p *ast.File) *ast.File { return rewriteFile(pattern, replace, p) }
-}
-
-// parseExpr parses s as an expression.
-// It might make sense to expand this to allow statement patterns,
-// but there are problems with preserving formatting and also
-// with what a wildcard for a statement looks like.
-func parseExpr(s, what string) ast.Expr {
- x, err := parser.ParseExpr(s)
- if err != nil {
- fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
- os.Exit(2)
- }
- return x
-}
-
-// Keep this function for debugging.
-/*
-func dump(msg string, val reflect.Value) {
- fmt.Printf("%s:\n", msg)
- ast.Print(fileSet, val.Interface())
- fmt.Println()
-}
-*/
-
-// rewriteFile applies the rewrite rule 'pattern -> replace' to an entire file.
-func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
- cmap := ast.NewCommentMap(fileSet, p, p.Comments)
- m := make(map[string]reflect.Value)
- pat := reflect.ValueOf(pattern)
- repl := reflect.ValueOf(replace)
-
- var rewriteVal func(val reflect.Value) reflect.Value
- rewriteVal = func(val reflect.Value) reflect.Value {
- // don't bother if val is invalid to start with
- if !val.IsValid() {
- return reflect.Value{}
- }
- for k := range m {
- delete(m, k)
- }
- val = apply(rewriteVal, val)
- if match(m, pat, val) {
- val = subst(m, repl, reflect.ValueOf(val.Interface().(ast.Node).Pos()))
- }
- return val
- }
-
- r := apply(rewriteVal, reflect.ValueOf(p)).Interface().(*ast.File)
- r.Comments = cmap.Filter(r).Comments() // recreate comments list
- return r
-}
-
-// set is a wrapper for x.Set(y); it protects the caller from panics if x cannot be changed to y.
-func set(x, y reflect.Value) {
- // don't bother if x cannot be set or y is invalid
- if !x.CanSet() || !y.IsValid() {
- return
- }
- defer func() {
- if x := recover(); x != nil {
- if s, ok := x.(string); ok &&
- (strings.Contains(s, "type mismatch") || strings.Contains(s, "not assignable")) {
- // x cannot be set to y - ignore this rewrite
- return
- }
- panic(x)
- }
- }()
- x.Set(y)
-}
-
-// Values/types for special cases.
-var (
- objectPtrNil = reflect.ValueOf((*ast.Object)(nil))
- scopePtrNil = reflect.ValueOf((*ast.Scope)(nil))
-
- identType = reflect.TypeOf((*ast.Ident)(nil))
- objectPtrType = reflect.TypeOf((*ast.Object)(nil))
- positionType = reflect.TypeOf(token.NoPos)
- callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
- scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
-)
-
-// apply replaces each AST field x in val with f(x), returning val.
-// To avoid extra conversions, f operates on the reflect.Value form.
-func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value {
- if !val.IsValid() {
- return reflect.Value{}
- }
-
- // *ast.Objects introduce cycles and are likely incorrect after
- // rewrite; don't follow them but replace with nil instead
- if val.Type() == objectPtrType {
- return objectPtrNil
- }
-
- // similarly for scopes: they are likely incorrect after a rewrite;
- // replace them with nil
- if val.Type() == scopePtrType {
- return scopePtrNil
- }
-
- switch v := reflect.Indirect(val); v.Kind() {
- case reflect.Slice:
- for i := 0; i < v.Len(); i++ {
- e := v.Index(i)
- set(e, f(e))
- }
- case reflect.Struct:
- for i := 0; i < v.NumField(); i++ {
- e := v.Field(i)
- set(e, f(e))
- }
- case reflect.Interface:
- e := v.Elem()
- set(v, f(e))
- }
- return val
-}
-
-func isWildcard(s string) bool {
- rune, size := utf8.DecodeRuneInString(s)
- return size == len(s) && unicode.IsLower(rune)
-}
-
-// match returns true if pattern matches val,
-// recording wildcard submatches in m.
-// If m == nil, match checks whether pattern == val.
-func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
- // Wildcard matches any expression. If it appears multiple
- // times in the pattern, it must match the same expression
- // each time.
- if m != nil && pattern.IsValid() && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name
- if isWildcard(name) && val.IsValid() {
- // wildcards only match valid (non-nil) expressions.
- if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() {
- if old, ok := m[name]; ok {
- return match(nil, old, val)
- }
- m[name] = val
- return true
- }
- }
- }
-
- // Otherwise, pattern and val must match recursively.
- if !pattern.IsValid() || !val.IsValid() {
- return !pattern.IsValid() && !val.IsValid()
- }
- if pattern.Type() != val.Type() {
- return false
- }
-
- // Special cases.
- switch pattern.Type() {
- case identType:
- // For identifiers, only the names need to match
- // (and none of the other *ast.Object information).
- // This is a common case, handle it all here instead
- // of recursing down any further via reflection.
- p := pattern.Interface().(*ast.Ident)
- v := val.Interface().(*ast.Ident)
- return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
- case objectPtrType, positionType:
- // object pointers and token positions always match
- return true
- case callExprType:
- // For calls, the Ellipsis fields (token.Position) must
- // match since that is how f(x) and f(x...) are different.
- // Check them here but fall through for the remaining fields.
- p := pattern.Interface().(*ast.CallExpr)
- v := val.Interface().(*ast.CallExpr)
- if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
- return false
- }
- }
-
- p := reflect.Indirect(pattern)
- v := reflect.Indirect(val)
- if !p.IsValid() || !v.IsValid() {
- return !p.IsValid() && !v.IsValid()
- }
-
- switch p.Kind() {
- case reflect.Slice:
- if p.Len() != v.Len() {
- return false
- }
- for i := 0; i < p.Len(); i++ {
- if !match(m, p.Index(i), v.Index(i)) {
- return false
- }
- }
- return true
-
- case reflect.Struct:
- for i := 0; i < p.NumField(); i++ {
- if !match(m, p.Field(i), v.Field(i)) {
- return false
- }
- }
- return true
-
- case reflect.Interface:
- return match(m, p.Elem(), v.Elem())
- }
-
- // Handle token integers, etc.
- return p.Interface() == v.Interface()
-}
-
-// subst returns a copy of pattern with values from m substituted in place
-// of wildcards and pos used as the position of tokens from the pattern.
-// if m == nil, subst returns a copy of pattern and doesn't change the line
-// number information.
-func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value) reflect.Value {
- if !pattern.IsValid() {
- return reflect.Value{}
- }
-
- // Wildcard gets replaced with map value.
- if m != nil && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name
- if isWildcard(name) {
- if old, ok := m[name]; ok {
- return subst(nil, old, reflect.Value{})
- }
- }
- }
-
- if pos.IsValid() && pattern.Type() == positionType {
- // use new position only if old position was valid in the first place
- if old := pattern.Interface().(token.Pos); !old.IsValid() {
- return pattern
- }
- return pos
- }
-
- // Otherwise copy.
- switch p := pattern; p.Kind() {
- case reflect.Slice:
- v := reflect.MakeSlice(p.Type(), p.Len(), p.Len())
- for i := 0; i < p.Len(); i++ {
- v.Index(i).Set(subst(m, p.Index(i), pos))
- }
- return v
-
- case reflect.Struct:
- v := reflect.New(p.Type()).Elem()
- for i := 0; i < p.NumField(); i++ {
- v.Field(i).Set(subst(m, p.Field(i), pos))
- }
- return v
-
- case reflect.Ptr:
- v := reflect.New(p.Type()).Elem()
- if elem := p.Elem(); elem.IsValid() {
- v.Set(subst(m, elem, pos).Addr())
- }
- return v
-
- case reflect.Interface:
- v := reflect.New(p.Type()).Elem()
- if elem := p.Elem(); elem.IsValid() {
- v.Set(subst(m, elem, pos))
- }
- return v
- }
-
- return pattern
-}
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index f67074016..ecbdd2734 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.7.1
+
+### Fixes
+- Bump go-yaml version to cover fixed ddos heuristic (#362) [95e431e]
+
## 1.7.0
### Features
diff --git a/vendor/github.com/onsi/gomega/go.mod b/vendor/github.com/onsi/gomega/go.mod
index 65eedf696..177a541c4 100644
--- a/vendor/github.com/onsi/gomega/go.mod
+++ b/vendor/github.com/onsi/gomega/go.mod
@@ -11,5 +11,6 @@ require (
golang.org/x/text v0.3.0 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
- gopkg.in/yaml.v2 v2.2.1
+ gopkg.in/yaml.v2 v2.2.4
)
+
diff --git a/vendor/github.com/onsi/gomega/go.sum b/vendor/github.com/onsi/gomega/go.sum
index b23f6ef02..bbcc05d3e 100644
--- a/vendor/github.com/onsi/gomega/go.sum
+++ b/vendor/github.com/onsi/gomega/go.sum
@@ -20,5 +20,5 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index b145768cf..85505f2ec 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -24,7 +24,7 @@ import (
"github.com/onsi/gomega/types"
)
-const GOMEGA_VERSION = "1.7.0"
+const GOMEGA_VERSION = "1.7.1"
const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
diff --git a/vendor/github.com/uber/jaeger-client-go/.travis.yml b/vendor/github.com/uber/jaeger-client-go/.travis.yml
index 0d7bdd9ab..e81cc8805 100644
--- a/vendor/github.com/uber/jaeger-client-go/.travis.yml
+++ b/vendor/github.com/uber/jaeger-client-go/.travis.yml
@@ -7,21 +7,22 @@ dist: trusty
matrix:
include:
- - go: 1.12.x
+ - go: 1.13.x
env:
- TESTS=true
- USE_DEP=true
- COVERAGE=true
- - go: 1.12.x
+ - go: 1.13.x
env:
- USE_DEP=true
- CROSSDOCK=true
- - go: 1.12.x
+ - go: 1.13.x
env:
- TESTS=true
- USE_DEP=false
- USE_GLIDE=true
- - go: 1.11.x
+ # test with previous version of Go
+ - go: 1.12.x
env:
- TESTS=true
- USE_DEP=true
diff --git a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
index 31b22e40c..c4590bf93 100644
--- a/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
+++ b/vendor/github.com/uber/jaeger-client-go/CHANGELOG.md
@@ -1,6 +1,45 @@
Changes by Version
==================
+2.20.0 (2019-11-06)
+-------------------
+
+## New Features
+
+- Allow all in-process spans of a trace to share sampling state (#443) -- Prithvi Raj
+
+ Sampling state is shared between all spans of the trace that are still in memory.
+ This allows implementation of delayed sampling decisions (see below).
+
+- Support delayed sampling decisions (#449) -- Yuri Shkuro
+
+ This is a large structural change to how the samplers work.
+ It allows some samplers to be executed multiple times on different
+ span events (like setting a tag) and make a positive sampling decision
+ later in the span life cycle, or even based on children spans.
+ See [README](./README.md#delayed-sampling) for more details.
+
+ There is a related minor change in behavior of the adaptive (per-operation) sampler,
+ which will no longer re-sample the trace when `span.SetOperation()` is called, i.e. the
+ operation used to make the sampling decision is always the one provided at span creation.
+
+- Add experimental tag matching sampler (#452) -- Yuri Shkuro
+
+ A sampler that can sample a trace based on a certain tag added to the root
+ span or one of its local (in-process) children. The sampler can be used with
+ another experimental `PrioritySampler` that allows multiple samplers to try
+ to make a sampling decision, in a certain priority order.
+
+- [log/zap] Report whether a trace was sampled (#445) -- Abhinav Gupta
+- Allow config.FromEnv() to enrich an existing config object (#436) -- Vineeth Reddy
+
+## Minor patches
+
+- Expose Sampler on Tracer and accept sampler options via Configuration (#460) -- Yuri Shkuro
+- Fix github.com/uber-go/atomic import (#464) -- Yuri Shkuro
+- Add nodejs to crossdock tests (#441) -- Bhavin Gandhi
+- Bump Go compiler version to 1.13 (#453) -- Yuri Shkuro
+
2.19.0 (2019-09-23)
-------------------
diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock
index 1ed86f4a7..5a42ebf16 100644
--- a/vendor/github.com/uber/jaeger-client-go/Gopkg.lock
+++ b/vendor/github.com/uber/jaeger-client-go/Gopkg.lock
@@ -2,6 +2,14 @@
[[projects]]
+ digest = "1:9f3b30d9f8e0d7040f729b82dcbc8f0dead820a133b3147ce355fc451f32d761"
+ name = "github.com/BurntSushi/toml"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
+ version = "v0.3.1"
+
+[[projects]]
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
name = "github.com/beorn7/perks"
packages = ["quantile"]
@@ -138,14 +146,6 @@
version = "v1.4.0"
[[projects]]
- digest = "1:a5158647b553c61877aa9ae74f4015000294e47981e6b8b07525edcbb0747c81"
- name = "github.com/uber-go/atomic"
- packages = ["."]
- pruneopts = "UT"
- revision = "df976f2515e274675050de7b3f42545de80594fd"
- version = "v1.4.0"
-
-[[projects]]
digest = "1:0ec60ffd594af00ba1660bc746aa0e443d27dd4003dee55f9d08a0b4ff5431a3"
name = "github.com/uber/jaeger-lib"
packages = [
@@ -158,23 +158,31 @@
version = "v2.2.0"
[[projects]]
- digest = "1:a5158647b553c61877aa9ae74f4015000294e47981e6b8b07525edcbb0747c81"
+ digest = "1:0bdcb0c740d79d400bd3f7946ac22a715c94db62b20bfd2e01cd50693aba0600"
name = "go.uber.org/atomic"
packages = ["."]
pruneopts = "UT"
- revision = "df976f2515e274675050de7b3f42545de80594fd"
- version = "v1.4.0"
+ revision = "9dc4df04d0d1c39369750a9f6c32c39560672089"
+ version = "v1.5.0"
[[projects]]
- digest = "1:60bf2a5e347af463c42ed31a493d817f8a72f102543060ed992754e689805d1a"
+ digest = "1:002ebc50f3ef475ac325e1904be931d9dcba6dc6d73b5682afce0c63436e3902"
name = "go.uber.org/multierr"
packages = ["."]
pruneopts = "UT"
- revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
- version = "v1.1.0"
+ revision = "c3fc3d02ec864719d8e25be2d7dde1e35a36aa27"
+ version = "v1.3.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:3032e90a153750ea149f68bf081f97ca738f041fba45c41c80737f572ffdf2f4"
+ name = "go.uber.org/tools"
+ packages = ["update-license"]
+ pruneopts = "UT"
+ revision = "2cfd321de3ee5d5f8a5fda2521d1703478334d98"
[[projects]]
- digest = "1:676160e6a4722b08e0e26b11521d575c2cb2b6f0c679e1ee6178c5d8dee51e5e"
+ digest = "1:6be13632ab4bd5842a097abb3aabac045a8601e19a10da4239e7d8bd83d4b83c"
name = "go.uber.org/zap"
packages = [
".",
@@ -185,8 +193,19 @@
"zapcore",
]
pruneopts = "UT"
- revision = "27376062155ad36be76b0f12cf1572a221d3a48c"
- version = "v1.10.0"
+ revision = "a6015e13fab9b744d96085308ce4e8f11bad1996"
+ version = "v1.12.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:21d7bad9b7da270fd2d50aba8971a041bd691165c95096a2a4c68db823cbc86a"
+ name = "golang.org/x/lint"
+ packages = [
+ ".",
+ "golint",
+ ]
+ pruneopts = "UT"
+ revision = "16217165b5de779cb6a5e4fc81fa9c1166fda457"
[[projects]]
branch = "master"
@@ -197,23 +216,81 @@
"context/ctxhttp",
]
pruneopts = "UT"
- revision = "aa69164e4478b84860dc6769c710c699c67058a3"
+ revision = "0deb6923b6d97481cb43bc1043fe5b72a0143032"
[[projects]]
branch = "master"
- digest = "1:712252802d318c8107d8f2136b99aa10feb17eca715245ed915199fbfc260155"
+ digest = "1:5dfb17d45415b7b8927382f53955a66f55f9d9d11557aa82f7f481d642ab247a"
name = "golang.org/x/sys"
packages = ["windows"]
pruneopts = "UT"
- revision = "0a153f010e6963173baba2306531d173aa843137"
+ revision = "f43be2a4598cf3a47be9f94f0c28197ed9eae611"
+
+[[projects]]
+ branch = "master"
+ digest = "1:bae8b3bf837d9d7f601776f37f44e031d46943677beff8fb2eb9c7317d44de2f"
+ name = "golang.org/x/tools"
+ packages = [
+ "go/analysis",
+ "go/analysis/passes/inspect",
+ "go/ast/astutil",
+ "go/ast/inspector",
+ "go/buildutil",
+ "go/gcexportdata",
+ "go/internal/gcimporter",
+ "go/internal/packagesdriver",
+ "go/packages",
+ "go/types/objectpath",
+ "go/types/typeutil",
+ "internal/fastwalk",
+ "internal/gopathwalk",
+ "internal/semver",
+ "internal/span",
+ ]
+ pruneopts = "UT"
+ revision = "8dbcdeb83d3faec5315146800b375c4962a42fc6"
[[projects]]
- digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
+ digest = "1:59f10c1537d2199d9115d946927fe31165959a95190849c82ff11e05803528b0"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
- revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
- version = "v2.2.2"
+ revision = "f221b8435cfb71e54062f6c6e99e9ade30b124d5"
+ version = "v2.2.4"
+
+[[projects]]
+ digest = "1:131158a88aad1f94854d0aa21a64af2802d0a470fb0f01cb33c04fafd2047111"
+ name = "honnef.co/go/tools"
+ packages = [
+ "arg",
+ "cmd/staticcheck",
+ "config",
+ "deprecated",
+ "facts",
+ "functions",
+ "go/types/typeutil",
+ "internal/cache",
+ "internal/passes/buildssa",
+ "internal/renameio",
+ "internal/sharedcheck",
+ "lint",
+ "lint/lintdsl",
+ "lint/lintutil",
+ "lint/lintutil/format",
+ "loader",
+ "printf",
+ "simple",
+ "ssa",
+ "ssautil",
+ "staticcheck",
+ "staticcheck/vrp",
+ "stylecheck",
+ "unused",
+ "version",
+ ]
+ pruneopts = "UT"
+ revision = "afd67930eec2a9ed3e9b19f684d17a062285f16a"
+ version = "2019.2.3"
[solve-meta]
analyzer-name = "dep"
@@ -229,10 +306,10 @@
"github.com/stretchr/testify/assert",
"github.com/stretchr/testify/require",
"github.com/stretchr/testify/suite",
- "github.com/uber-go/atomic",
"github.com/uber/jaeger-lib/metrics",
"github.com/uber/jaeger-lib/metrics/metricstest",
"github.com/uber/jaeger-lib/metrics/prometheus",
+ "go.uber.org/atomic",
"go.uber.org/zap",
"go.uber.org/zap/zapcore",
]
diff --git a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml
index 3e6ac35ae..1fed7f814 100644
--- a/vendor/github.com/uber/jaeger-client-go/Gopkg.toml
+++ b/vendor/github.com/uber/jaeger-client-go/Gopkg.toml
@@ -15,7 +15,7 @@
version = "^1.1.3"
[[constraint]]
- name = "github.com/uber-go/atomic"
+ name = "go.uber.org/atomic"
version = "^1"
[[constraint]]
diff --git a/vendor/github.com/uber/jaeger-client-go/Makefile b/vendor/github.com/uber/jaeger-client-go/Makefile
index 74e11787a..0cfe6a5f6 100644
--- a/vendor/github.com/uber/jaeger-client-go/Makefile
+++ b/vendor/github.com/uber/jaeger-client-go/Makefile
@@ -1,5 +1,5 @@
PROJECT_ROOT=github.com/uber/jaeger-client-go
-PACKAGES := $(shell go list ./... | awk -F/ 'NR>1 {print "./"$$4"/..."}' | grep -v -e ./thrift-gen/... -e ./thrift/... | sort -u)
+PACKAGES := . $(shell go list ./... | awk -F/ 'NR>1 {print "./"$$4"/..."}' | grep -v -e ./thrift-gen/... -e ./thrift/... | sort -u)
# all .go files that don't exist in hidden directories
ALL_SRC := $(shell find . -name "*.go" | grep -v -e vendor -e thrift-gen -e ./thrift/ \
-e ".*/\..*" \
@@ -125,3 +125,4 @@ ifeq ($(CI_SKIP_LINT),true)
else
make lint
endif
+
diff --git a/vendor/github.com/uber/jaeger-client-go/README.md b/vendor/github.com/uber/jaeger-client-go/README.md
index 604d4b571..a3366114d 100644
--- a/vendor/github.com/uber/jaeger-client-go/README.md
+++ b/vendor/github.com/uber/jaeger-client-go/README.md
@@ -182,6 +182,29 @@ are available:
1. `RateLimitingSampler` can be used to allow only a certain fixed
number of traces to be sampled per second.
+#### Delayed sampling
+
+Version 2.20 introduced the ability to delay sampling decisions in the life cycle
+of the root span. It involves several features and architectural changes:
+ * **Shared sampling state**: the sampling state is shared across all local
+ (i.e. in-process) spans for a given trace.
+ * **New `SamplerV2` API** allows the sampler to be called at multiple points
+ in the life cycle of a span:
+ * on span creation
+ * on overwriting span operation name
+ * on setting span tags
+ * on finishing the span
+ * **Final/non-final sampling state**: the new `SamplerV2` API allows the sampler
+ to indicate if the negative sampling decision is final or not (positive sampling
+ decisions are always final). If the decision is not final, the sampler will be
+ called again on further span life cycle events, like setting tags.
+
+These new features are used in the experimental `x.TagMatchingSampler`, which
+can sample a trace based on a certain tag added to the root
+span or one of its local (in-process) children. The sampler can be used with
+another experimental `x.PrioritySampler` that allows multiple samplers to try
+to make a sampling decision, in a certain priority order.
+
### Baggage Injection
The OpenTracing spec allows for [baggage][baggage], which are key value pairs that are added
diff --git a/vendor/github.com/uber/jaeger-client-go/config/config.go b/vendor/github.com/uber/jaeger-client-go/config/config.go
index 6bce1b3b0..965f7c3ee 100644
--- a/vendor/github.com/uber/jaeger-client-go/config/config.go
+++ b/vendor/github.com/uber/jaeger-client-go/config/config.go
@@ -86,6 +86,9 @@ type SamplerConfig struct {
// jaeger-agent for the appropriate sampling strategy.
// Can be set by exporting an environment variable named JAEGER_SAMPLER_REFRESH_INTERVAL
SamplingRefreshInterval time.Duration `yaml:"samplingRefreshInterval"`
+
+ // Options can be used to programmatically pass additional options to the Remote sampler.
+ Options []jaeger.SamplerOption
}
// ReporterConfig configures the reporter. All fields are optional.
@@ -357,6 +360,7 @@ func (sc *SamplerConfig) NewSampler(
if sc.SamplingRefreshInterval != 0 {
options = append(options, jaeger.SamplerOptions.SamplingRefreshInterval(sc.SamplingRefreshInterval))
}
+ options = append(options, sc.Options...)
return jaeger.NewRemotelyControlledSampler(serviceName, options...), nil
}
return nil, fmt.Errorf("Unknown sampler type %v", sc.Type)
diff --git a/vendor/github.com/uber/jaeger-client-go/config/config_env.go b/vendor/github.com/uber/jaeger-client-go/config/config_env.go
index 14d69b11d..a729bd8fe 100644
--- a/vendor/github.com/uber/jaeger-client-go/config/config_env.go
+++ b/vendor/github.com/uber/jaeger-client-go/config/config_env.go
@@ -52,7 +52,11 @@ const (
// FromEnv uses environment variables to set the tracer's Configuration
func FromEnv() (*Configuration, error) {
c := &Configuration{}
+ return c.FromEnv()
+}
+// FromEnv uses environment variables and overrides existing tracer's Configuration
+func (c *Configuration) FromEnv() (*Configuration, error) {
if e := os.Getenv(envServiceName); e != "" {
c.ServiceName = e
}
@@ -77,13 +81,21 @@ func FromEnv() (*Configuration, error) {
c.Tags = parseTags(e)
}
- if s, err := samplerConfigFromEnv(); err == nil {
+ if c.Sampler == nil {
+ c.Sampler = &SamplerConfig{}
+ }
+
+ if s, err := c.Sampler.samplerConfigFromEnv(); err == nil {
c.Sampler = s
} else {
return nil, errors.Wrap(err, "cannot obtain sampler config from env")
}
- if r, err := reporterConfigFromEnv(); err == nil {
+ if c.Reporter == nil {
+ c.Reporter = &ReporterConfig{}
+ }
+
+ if r, err := c.Reporter.reporterConfigFromEnv(); err == nil {
c.Reporter = r
} else {
return nil, errors.Wrap(err, "cannot obtain reporter config from env")
@@ -93,9 +105,7 @@ func FromEnv() (*Configuration, error) {
}
// samplerConfigFromEnv creates a new SamplerConfig based on the environment variables
-func samplerConfigFromEnv() (*SamplerConfig, error) {
- sc := &SamplerConfig{}
-
+func (sc *SamplerConfig) samplerConfigFromEnv() (*SamplerConfig, error) {
if e := os.Getenv(envSamplerType); e != "" {
sc.Type = e
}
@@ -135,9 +145,7 @@ func samplerConfigFromEnv() (*SamplerConfig, error) {
}
// reporterConfigFromEnv creates a new ReporterConfig based on the environment variables
-func reporterConfigFromEnv() (*ReporterConfig, error) {
- rc := &ReporterConfig{}
-
+func (rc *ReporterConfig) reporterConfigFromEnv() (*ReporterConfig, error) {
if e := os.Getenv(envReporterMaxQueueSize); e != "" {
if value, err := strconv.ParseInt(e, 10, 0); err == nil {
rc.QueueSize = int(value)
diff --git a/vendor/github.com/uber/jaeger-client-go/constants.go b/vendor/github.com/uber/jaeger-client-go/constants.go
index e95b2ba09..0da47b02f 100644
--- a/vendor/github.com/uber/jaeger-client-go/constants.go
+++ b/vendor/github.com/uber/jaeger-client-go/constants.go
@@ -22,7 +22,7 @@ import (
const (
// JaegerClientVersion is the version of the client library reported as Span tag.
- JaegerClientVersion = "Go-2.19.0"
+ JaegerClientVersion = "Go-2.20.0"
// JaegerClientVersionTagKey is the name of the tag used to report client version.
JaegerClientVersionTagKey = "jaeger.version"
diff --git a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go
index 6ce1caf87..f0f1afe2f 100644
--- a/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go
+++ b/vendor/github.com/uber/jaeger-client-go/jaeger_thrift_span.go
@@ -35,7 +35,7 @@ func BuildJaegerThrift(span *Span) *j.Span {
SpanId: int64(span.context.spanID),
ParentSpanId: int64(span.context.parentID),
OperationName: span.operationName,
- Flags: int32(span.context.flags),
+ Flags: int32(span.context.samplingState.flags()),
StartTime: startTime,
Duration: duration,
Tags: buildTags(span.tags, span.tracer.options.maxTagValueLength),
diff --git a/vendor/github.com/uber/jaeger-client-go/metrics.go b/vendor/github.com/uber/jaeger-client-go/metrics.go
index e56db9b73..50e4e22d6 100644
--- a/vendor/github.com/uber/jaeger-client-go/metrics.go
+++ b/vendor/github.com/uber/jaeger-client-go/metrics.go
@@ -26,6 +26,9 @@ type Metrics struct {
// Number of traces started by this tracer as not sampled
TracesStartedNotSampled metrics.Counter `metric:"traces" tags:"state=started,sampled=n" help:"Number of traces started by this tracer as not sampled"`
+ // Number of traces started by this tracer with delayed sampling
+ TracesStartedDelayedSampling metrics.Counter `metric:"traces" tags:"state=started,sampled=n" help:"Number of traces started by this tracer with delayed sampling"`
+
// Number of externally started sampled traces this tracer joined
TracesJoinedSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=y" help:"Number of externally started sampled traces this tracer joined"`
@@ -33,13 +36,22 @@ type Metrics struct {
TracesJoinedNotSampled metrics.Counter `metric:"traces" tags:"state=joined,sampled=n" help:"Number of externally started not-sampled traces this tracer joined"`
// Number of sampled spans started by this tracer
- SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y" help:"Number of sampled spans started by this tracer"`
+ SpansStartedSampled metrics.Counter `metric:"started_spans" tags:"sampled=y" help:"Number of spans started by this tracer as sampled"`
+
+ // Number of not sampled spans started by this tracer
+ SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n" help:"Number of spans started by this tracer as not sampled"`
+
+ // Number of spans with delayed sampling started by this tracer
+ SpansStartedDelayedSampling metrics.Counter `metric:"started_spans" tags:"sampled=delayed" help:"Number of spans started by this tracer with delayed sampling"`
- // Number of unsampled spans started by this tracer
- SpansStartedNotSampled metrics.Counter `metric:"started_spans" tags:"sampled=n" help:"Number of unsampled spans started by this tracer"`
+ // Number of spans finished by this tracer
+ SpansFinishedSampled metrics.Counter `metric:"finished_spans" tags:"sampled=y" help:"Number of sampled spans finished by this tracer"`
+
+ // Number of spans finished by this tracer
+ SpansFinishedNotSampled metrics.Counter `metric:"finished_spans" tags:"sampled=n" help:"Number of not-sampled spans finished by this tracer"`
// Number of spans finished by this tracer
- SpansFinished metrics.Counter `metric:"finished_spans" help:"Number of spans finished by this tracer"`
+ SpansFinishedDelayedSampling metrics.Counter `metric:"finished_spans" tags:"sampled=delayed" help:"Number of spans with delayed sampling finished by this tracer"`
// Number of errors decoding tracing context
DecodingErrors metrics.Counter `metric:"span_context_decoding_errors" help:"Number of errors decoding tracing context"`
diff --git a/vendor/github.com/uber/jaeger-client-go/propagation.go b/vendor/github.com/uber/jaeger-client-go/propagation.go
index 5b50cfb71..42fd64b58 100644
--- a/vendor/github.com/uber/jaeger-client-go/propagation.go
+++ b/vendor/github.com/uber/jaeger-client-go/propagation.go
@@ -193,7 +193,7 @@ func (p *BinaryPropagator) Inject(
if err := binary.Write(carrier, binary.BigEndian, sc.parentID); err != nil {
return err
}
- if err := binary.Write(carrier, binary.BigEndian, sc.flags); err != nil {
+ if err := binary.Write(carrier, binary.BigEndian, sc.samplingState.flags()); err != nil {
return err
}
@@ -222,6 +222,7 @@ func (p *BinaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, er
return emptyContext, opentracing.ErrInvalidCarrier
}
var ctx SpanContext
+ ctx.samplingState = &samplingState{}
if err := binary.Read(carrier, binary.BigEndian, &ctx.traceID); err != nil {
return emptyContext, opentracing.ErrSpanContextCorrupted
@@ -232,9 +233,12 @@ func (p *BinaryPropagator) Extract(abstractCarrier interface{}) (SpanContext, er
if err := binary.Read(carrier, binary.BigEndian, &ctx.parentID); err != nil {
return emptyContext, opentracing.ErrSpanContextCorrupted
}
- if err := binary.Read(carrier, binary.BigEndian, &ctx.flags); err != nil {
+
+ var flags byte
+ if err := binary.Read(carrier, binary.BigEndian, &flags); err != nil {
return emptyContext, opentracing.ErrSpanContextCorrupted
}
+ ctx.samplingState.setFlags(flags)
// Handle the baggage items
var numBaggage int32
diff --git a/vendor/github.com/uber/jaeger-client-go/reporter.go b/vendor/github.com/uber/jaeger-client-go/reporter.go
index 27163ebe4..0b78cec20 100644
--- a/vendor/github.com/uber/jaeger-client-go/reporter.go
+++ b/vendor/github.com/uber/jaeger-client-go/reporter.go
@@ -28,6 +28,8 @@ import (
// Reporter is called by the tracer when a span is completed to report the span to the tracing collector.
type Reporter interface {
// Report submits a new span to collectors, possibly asynchronously and/or with buffering.
+ // If the reporter is processing Span asynchronously then it needs to Retain() the span,
+ // and then Release() it when no longer needed, to avoid span data corruption.
Report(span *Span)
// Close does a clean shutdown of the reporter, flushing any traces that may be buffered in memory.
diff --git a/vendor/github.com/uber/jaeger-client-go/sampler.go b/vendor/github.com/uber/jaeger-client-go/sampler.go
index ea6984e02..6195d59c5 100644
--- a/vendor/github.com/uber/jaeger-client-go/sampler.go
+++ b/vendor/github.com/uber/jaeger-client-go/sampler.go
@@ -17,19 +17,14 @@ package jaeger
import (
"fmt"
"math"
- "net/url"
"sync"
- "sync/atomic"
- "time"
- "github.com/uber/jaeger-client-go/log"
"github.com/uber/jaeger-client-go/thrift-gen/sampling"
"github.com/uber/jaeger-client-go/utils"
)
const (
- defaultSamplingRefreshInterval = time.Minute
- defaultMaxOperations = 2000
+ defaultMaxOperations = 2000
)
// Sampler decides whether a new trace should be sampled or not.
@@ -47,9 +42,7 @@ type Sampler interface {
// Equal checks if the `other` sampler is functionally equivalent
// to this sampler.
- // TODO remove this function. This function is used to determine if 2 samplers are equivalent
- // which does not bode well with the adaptive sampler which has to create all the composite samplers
- // for the comparison to occur. This is expensive to do if only one sampler has changed.
+ // TODO (breaking change) remove this function. See PerOperationSampler.Equals for explanation.
Equal(other Sampler) bool
}
@@ -57,17 +50,23 @@ type Sampler interface {
// ConstSampler is a sampler that always makes the same decision.
type ConstSampler struct {
+ legacySamplerV1Base
Decision bool
tags []Tag
}
// NewConstSampler creates a ConstSampler.
-func NewConstSampler(sample bool) Sampler {
+func NewConstSampler(sample bool) *ConstSampler {
tags := []Tag{
{key: SamplerTypeTagKey, value: SamplerTypeConst},
{key: SamplerParamTagKey, value: sample},
}
- return &ConstSampler{Decision: sample, tags: tags}
+ s := &ConstSampler{
+ Decision: sample,
+ tags: tags,
+ }
+ s.delegate = s.IsSampled
+ return s
}
// IsSampled implements IsSampled() of Sampler.
@@ -88,11 +87,17 @@ func (s *ConstSampler) Equal(other Sampler) bool {
return false
}
+// String is used to log sampler details.
+func (s *ConstSampler) String() string {
+ return fmt.Sprintf("ConstSampler(decision=%t)", s.Decision)
+}
+
// -----------------------
// ProbabilisticSampler is a sampler that randomly samples a certain percentage
// of traces.
type ProbabilisticSampler struct {
+ legacySamplerV1Base
samplingRate float64
samplingBoundary uint64
tags []Tag
@@ -114,16 +119,19 @@ func NewProbabilisticSampler(samplingRate float64) (*ProbabilisticSampler, error
}
func newProbabilisticSampler(samplingRate float64) *ProbabilisticSampler {
- samplingRate = math.Max(0.0, math.Min(samplingRate, 1.0))
- tags := []Tag{
+ s := new(ProbabilisticSampler)
+ s.delegate = s.IsSampled
+ return s.init(samplingRate)
+}
+
+func (s *ProbabilisticSampler) init(samplingRate float64) *ProbabilisticSampler {
+ s.samplingRate = math.Max(0.0, math.Min(samplingRate, 1.0))
+ s.samplingBoundary = uint64(float64(maxRandomNumber) * s.samplingRate)
+ s.tags = []Tag{
{key: SamplerTypeTagKey, value: SamplerTypeProbabilistic},
- {key: SamplerParamTagKey, value: samplingRate},
- }
- return &ProbabilisticSampler{
- samplingRate: samplingRate,
- samplingBoundary: uint64(float64(maxRandomNumber) * samplingRate),
- tags: tags,
+ {key: SamplerParamTagKey, value: s.samplingRate},
}
+ return s
}
// SamplingRate returns the sampling probability this sampled was constructed with.
@@ -149,65 +157,104 @@ func (s *ProbabilisticSampler) Equal(other Sampler) bool {
return false
}
+// Update modifies in-place the sampling rate. Locking must be done externally.
+func (s *ProbabilisticSampler) Update(samplingRate float64) error {
+ if samplingRate < 0.0 || samplingRate > 1.0 {
+ return fmt.Errorf("Sampling Rate must be between 0.0 and 1.0, received %f", samplingRate)
+ }
+ s.init(samplingRate)
+ return nil
+}
+
+// String is used to log sampler details.
+func (s *ProbabilisticSampler) String() string {
+ return fmt.Sprintf("ProbabilisticSampler(samplingRate=%v)", s.samplingRate)
+}
+
// -----------------------
-type rateLimitingSampler struct {
+// RateLimitingSampler samples at most maxTracesPerSecond. The distribution of sampled traces follows
+// burstiness of the service, i.e. a service with uniformly distributed requests will have those
+// requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a
+// number of sequential requests can be sampled each second.
+type RateLimitingSampler struct {
+ legacySamplerV1Base
maxTracesPerSecond float64
- rateLimiter utils.RateLimiter
+ rateLimiter *utils.ReconfigurableRateLimiter
tags []Tag
}
-// NewRateLimitingSampler creates a sampler that samples at most maxTracesPerSecond. The distribution of sampled
-// traces follows burstiness of the service, i.e. a service with uniformly distributed requests will have those
-// requests sampled uniformly as well, but if requests are bursty, especially sub-second, then a number of
-// sequential requests can be sampled each second.
-func NewRateLimitingSampler(maxTracesPerSecond float64) Sampler {
- tags := []Tag{
+// NewRateLimitingSampler creates new RateLimitingSampler.
+func NewRateLimitingSampler(maxTracesPerSecond float64) *RateLimitingSampler {
+ s := new(RateLimitingSampler)
+ s.delegate = s.IsSampled
+ return s.init(maxTracesPerSecond)
+}
+
+func (s *RateLimitingSampler) init(maxTracesPerSecond float64) *RateLimitingSampler {
+ if s.rateLimiter == nil {
+ s.rateLimiter = utils.NewRateLimiter(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0))
+ } else {
+ s.rateLimiter.Update(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0))
+ }
+ s.maxTracesPerSecond = maxTracesPerSecond
+ s.tags = []Tag{
{key: SamplerTypeTagKey, value: SamplerTypeRateLimiting},
{key: SamplerParamTagKey, value: maxTracesPerSecond},
}
- return &rateLimitingSampler{
- maxTracesPerSecond: maxTracesPerSecond,
- rateLimiter: utils.NewRateLimiter(maxTracesPerSecond, math.Max(maxTracesPerSecond, 1.0)),
- tags: tags,
- }
+ return s
}
// IsSampled implements IsSampled() of Sampler.
-func (s *rateLimitingSampler) IsSampled(id TraceID, operation string) (bool, []Tag) {
+func (s *RateLimitingSampler) IsSampled(id TraceID, operation string) (bool, []Tag) {
return s.rateLimiter.CheckCredit(1.0), s.tags
}
-func (s *rateLimitingSampler) Close() {
+// Update reconfigures the rate limiter, while preserving its accumulated balance.
+// Locking must be done externally.
+func (s *RateLimitingSampler) Update(maxTracesPerSecond float64) {
+ if s.maxTracesPerSecond != maxTracesPerSecond {
+ s.init(maxTracesPerSecond)
+ }
+}
+
+// Close does nothing.
+func (s *RateLimitingSampler) Close() {
// nothing to do
}
-func (s *rateLimitingSampler) Equal(other Sampler) bool {
- if o, ok := other.(*rateLimitingSampler); ok {
+// Equal compares with another sampler.
+func (s *RateLimitingSampler) Equal(other Sampler) bool {
+ if o, ok := other.(*RateLimitingSampler); ok {
return s.maxTracesPerSecond == o.maxTracesPerSecond
}
return false
}
+// String is used to log sampler details.
+func (s *RateLimitingSampler) String() string {
+ return fmt.Sprintf("RateLimitingSampler(maxTracesPerSecond=%v)", s.maxTracesPerSecond)
+}
+
// -----------------------
-// GuaranteedThroughputProbabilisticSampler is a sampler that leverages both probabilisticSampler and
-// rateLimitingSampler. The rateLimitingSampler is used as a guaranteed lower bound sampler such that
+// GuaranteedThroughputProbabilisticSampler is a sampler that leverages both ProbabilisticSampler and
+// RateLimitingSampler. The RateLimitingSampler is used as a guaranteed lower bound sampler such that
// every operation is sampled at least once in a time interval defined by the lowerBound. ie a lowerBound
// of 1.0 / (60 * 10) will sample an operation at least once every 10 minutes.
//
-// The probabilisticSampler is given higher priority when tags are emitted, ie. if IsSampled() for both
-// samplers return true, the tags for probabilisticSampler will be used.
+// The ProbabilisticSampler is given higher priority when tags are emitted, ie. if IsSampled() for both
+// samplers return true, the tags for ProbabilisticSampler will be used.
type GuaranteedThroughputProbabilisticSampler struct {
probabilisticSampler *ProbabilisticSampler
- lowerBoundSampler Sampler
+ lowerBoundSampler *RateLimitingSampler
tags []Tag
samplingRate float64
lowerBound float64
}
// NewGuaranteedThroughputProbabilisticSampler returns a delegating sampler that applies both
-// probabilisticSampler and rateLimitingSampler.
+// ProbabilisticSampler and RateLimitingSampler.
func NewGuaranteedThroughputProbabilisticSampler(
lowerBound, samplingRate float64,
) (*GuaranteedThroughputProbabilisticSampler, error) {
@@ -224,8 +271,14 @@ func newGuaranteedThroughputProbabilisticSampler(lowerBound, samplingRate float6
}
func (s *GuaranteedThroughputProbabilisticSampler) setProbabilisticSampler(samplingRate float64) {
- if s.probabilisticSampler == nil || s.samplingRate != samplingRate {
+ if s.probabilisticSampler == nil {
s.probabilisticSampler = newProbabilisticSampler(samplingRate)
+ } else if s.samplingRate != samplingRate {
+ s.probabilisticSampler.init(samplingRate)
+ }
+ // since we don't validate samplingRate, sampler may have clamped it to [0, 1] interval
+ samplingRate = s.probabilisticSampler.SamplingRate()
+ if s.samplingRate != samplingRate || s.tags == nil {
s.samplingRate = s.probabilisticSampler.SamplingRate()
s.tags = []Tag{
{key: SamplerTypeTagKey, value: SamplerTypeLowerBound},
@@ -252,7 +305,7 @@ func (s *GuaranteedThroughputProbabilisticSampler) Close() {
// Equal implements Equal() of Sampler.
func (s *GuaranteedThroughputProbabilisticSampler) Equal(other Sampler) bool {
- // NB The Equal() function is expensive and will be removed. See adaptiveSampler.Equal() for
+ // NB The Equal() function is expensive and will be removed. See PerOperationSampler.Equal() for
// more information.
return false
}
@@ -261,52 +314,116 @@ func (s *GuaranteedThroughputProbabilisticSampler) Equal(other Sampler) bool {
func (s *GuaranteedThroughputProbabilisticSampler) update(lowerBound, samplingRate float64) {
s.setProbabilisticSampler(samplingRate)
if s.lowerBound != lowerBound {
- s.lowerBoundSampler = NewRateLimitingSampler(lowerBound)
+ s.lowerBoundSampler.Update(lowerBound)
s.lowerBound = lowerBound
}
}
// -----------------------
-type adaptiveSampler struct {
+// PerOperationSampler is a delegating sampler that applies GuaranteedThroughputProbabilisticSampler
+// on a per-operation basis.
+type PerOperationSampler struct {
sync.RWMutex
samplers map[string]*GuaranteedThroughputProbabilisticSampler
defaultSampler *ProbabilisticSampler
lowerBound float64
maxOperations int
+
+ // see description in PerOperationSamplerParams
+ operationNameLateBinding bool
}
-// NewAdaptiveSampler returns a delegating sampler that applies both probabilisticSampler and
-// rateLimitingSampler via the guaranteedThroughputProbabilisticSampler. This sampler keeps track of all
-// operations and delegates calls to the respective guaranteedThroughputProbabilisticSampler.
-func NewAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) (Sampler, error) {
- return newAdaptiveSampler(strategies, maxOperations), nil
+// NewAdaptiveSampler returns a new PerOperationSampler.
+// Deprecated: please use NewPerOperationSampler.
+func NewAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) (*PerOperationSampler, error) {
+ return NewPerOperationSampler(PerOperationSamplerParams{
+ MaxOperations: maxOperations,
+ Strategies: strategies,
+ }), nil
}
-func newAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies, maxOperations int) Sampler {
+// PerOperationSamplerParams defines parameters when creating PerOperationSampler.
+type PerOperationSamplerParams struct {
+ // Max number of operations that will be tracked. Other operations will be given default strategy.
+ MaxOperations int
+
+ // Opt-in feature for applications that require late binding of span name via explicit call to SetOperationName.
+ // When this feature is enabled, the sampler will return retryable=true from OnCreateSpan(), thus leaving
+ // the sampling decision as non-final (and the span as writeable). This may lead to degraded performance
+ // in applications that always provide the correct span name on trace creation.
+ //
+ // For backwards compatibility this option is off by default.
+ OperationNameLateBinding bool
+
+ // Initial configuration of the sampling strategies (usually retrieved from the backend by Remote Sampler).
+ Strategies *sampling.PerOperationSamplingStrategies
+}
+
+// NewPerOperationSampler returns a new PerOperationSampler.
+func NewPerOperationSampler(params PerOperationSamplerParams) *PerOperationSampler {
samplers := make(map[string]*GuaranteedThroughputProbabilisticSampler)
- for _, strategy := range strategies.PerOperationStrategies {
+ for _, strategy := range params.Strategies.PerOperationStrategies {
sampler := newGuaranteedThroughputProbabilisticSampler(
- strategies.DefaultLowerBoundTracesPerSecond,
+ params.Strategies.DefaultLowerBoundTracesPerSecond,
strategy.ProbabilisticSampling.SamplingRate,
)
samplers[strategy.Operation] = sampler
}
- return &adaptiveSampler{
- samplers: samplers,
- defaultSampler: newProbabilisticSampler(strategies.DefaultSamplingProbability),
- lowerBound: strategies.DefaultLowerBoundTracesPerSecond,
- maxOperations: maxOperations,
+ return &PerOperationSampler{
+ samplers: samplers,
+ defaultSampler: newProbabilisticSampler(params.Strategies.DefaultSamplingProbability),
+ lowerBound: params.Strategies.DefaultLowerBoundTracesPerSecond,
+ maxOperations: params.MaxOperations,
+ operationNameLateBinding: params.OperationNameLateBinding,
}
}
-func (s *adaptiveSampler) IsSampled(id TraceID, operation string) (bool, []Tag) {
+// IsSampled is not used and only exists to match Sampler V1 API.
+// TODO (breaking change) remove when upgrading everything to SamplerV2
+func (s *PerOperationSampler) IsSampled(id TraceID, operation string) (bool, []Tag) {
+ return false, nil
+}
+
+func (s *PerOperationSampler) trySampling(span *Span, operationName string) (bool, []Tag) {
+ samplerV1 := s.getSamplerForOperation(operationName)
+ var sampled bool
+ var tags []Tag
+ if span.context.samplingState.isLocalRootSpan(span.context.spanID) {
+ sampled, tags = samplerV1.IsSampled(span.context.TraceID(), operationName)
+ }
+ return sampled, tags
+}
+
+// OnCreateSpan implements OnCreateSpan of SamplerV2.
+func (s *PerOperationSampler) OnCreateSpan(span *Span) SamplingDecision {
+ sampled, tags := s.trySampling(span, span.OperationName())
+ return SamplingDecision{Sample: sampled, Retryable: s.operationNameLateBinding, Tags: tags}
+}
+
+// OnSetOperationName implements OnSetOperationName of SamplerV2.
+func (s *PerOperationSampler) OnSetOperationName(span *Span, operationName string) SamplingDecision {
+ sampled, tags := s.trySampling(span, operationName)
+ return SamplingDecision{Sample: sampled, Retryable: false, Tags: tags}
+}
+
+// OnSetTag implements OnSetTag of SamplerV2.
+func (s *PerOperationSampler) OnSetTag(span *Span, key string, value interface{}) SamplingDecision {
+ return SamplingDecision{Sample: false, Retryable: true}
+}
+
+// OnFinishSpan implements OnFinishSpan of SamplerV2.
+func (s *PerOperationSampler) OnFinishSpan(span *Span) SamplingDecision {
+ return SamplingDecision{Sample: false, Retryable: true}
+}
+
+func (s *PerOperationSampler) getSamplerForOperation(operation string) Sampler {
s.RLock()
sampler, ok := s.samplers[operation]
if ok {
defer s.RUnlock()
- return sampler.IsSampled(id, operation)
+ return sampler
}
s.RUnlock()
s.Lock()
@@ -315,18 +432,19 @@ func (s *adaptiveSampler) IsSampled(id TraceID, operation string) (bool, []Tag)
// Check if sampler has already been created
sampler, ok = s.samplers[operation]
if ok {
- return sampler.IsSampled(id, operation)
+ return sampler
}
// Store only up to maxOperations of unique ops.
if len(s.samplers) >= s.maxOperations {
- return s.defaultSampler.IsSampled(id, operation)
+ return s.defaultSampler
}
newSampler := newGuaranteedThroughputProbabilisticSampler(s.lowerBound, s.defaultSampler.SamplingRate())
s.samplers[operation] = newSampler
- return newSampler.IsSampled(id, operation)
+ return newSampler
}
-func (s *adaptiveSampler) Close() {
+// Close invokes Close on all underlying samplers.
+func (s *PerOperationSampler) Close() {
s.Lock()
defer s.Unlock()
for _, sampler := range s.samplers {
@@ -335,16 +453,18 @@ func (s *adaptiveSampler) Close() {
s.defaultSampler.Close()
}
-func (s *adaptiveSampler) Equal(other Sampler) bool {
- // NB The Equal() function is overly expensive for adaptiveSampler since it's composed of multiple
+// Equal is not used.
+// TODO (breaking change) remove this in the future
+func (s *PerOperationSampler) Equal(other Sampler) bool {
+ // NB The Equal() function is overly expensive for PerOperationSampler since it's composed of multiple
// samplers which all need to be initialized before this function can be called for a comparison.
- // Therefore, adaptiveSampler uses the update() function to only alter the samplers that need
+ // Therefore, PerOperationSampler uses the update() function to only alter the samplers that need
// changing. Hence this function always returns false so that the update function can be called.
// Once the Equal() function is removed from the Sampler API, this will no longer be needed.
return false
}
-func (s *adaptiveSampler) update(strategies *sampling.PerOperationSamplingStrategies) {
+func (s *PerOperationSampler) update(strategies *sampling.PerOperationSamplingStrategies) {
s.Lock()
defer s.Unlock()
newSamplers := map[string]*GuaranteedThroughputProbabilisticSampler{}
@@ -369,191 +489,3 @@ func (s *adaptiveSampler) update(strategies *sampling.PerOperationSamplingStrate
}
s.samplers = newSamplers
}
-
-// -----------------------
-
-// RemotelyControlledSampler is a delegating sampler that polls a remote server
-// for the appropriate sampling strategy, constructs a corresponding sampler and
-// delegates to it for sampling decisions.
-type RemotelyControlledSampler struct {
- // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment.
- // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq
- closed int64 // 0 - not closed, 1 - closed
-
- sync.RWMutex
- samplerOptions
-
- serviceName string
- manager sampling.SamplingManager
- doneChan chan *sync.WaitGroup
-}
-
-type httpSamplingManager struct {
- serverURL string
-}
-
-func (s *httpSamplingManager) GetSamplingStrategy(serviceName string) (*sampling.SamplingStrategyResponse, error) {
- var out sampling.SamplingStrategyResponse
- v := url.Values{}
- v.Set("service", serviceName)
- if err := utils.GetJSON(s.serverURL+"?"+v.Encode(), &out); err != nil {
- return nil, err
- }
- return &out, nil
-}
-
-// NewRemotelyControlledSampler creates a sampler that periodically pulls
-// the sampling strategy from an HTTP sampling server (e.g. jaeger-agent).
-func NewRemotelyControlledSampler(
- serviceName string,
- opts ...SamplerOption,
-) *RemotelyControlledSampler {
- options := applySamplerOptions(opts...)
- sampler := &RemotelyControlledSampler{
- samplerOptions: options,
- serviceName: serviceName,
- manager: &httpSamplingManager{serverURL: options.samplingServerURL},
- doneChan: make(chan *sync.WaitGroup),
- }
- go sampler.pollController()
- return sampler
-}
-
-func applySamplerOptions(opts ...SamplerOption) samplerOptions {
- options := samplerOptions{}
- for _, option := range opts {
- option(&options)
- }
- if options.sampler == nil {
- options.sampler = newProbabilisticSampler(0.001)
- }
- if options.logger == nil {
- options.logger = log.NullLogger
- }
- if options.maxOperations <= 0 {
- options.maxOperations = defaultMaxOperations
- }
- if options.samplingServerURL == "" {
- options.samplingServerURL = DefaultSamplingServerURL
- }
- if options.metrics == nil {
- options.metrics = NewNullMetrics()
- }
- if options.samplingRefreshInterval <= 0 {
- options.samplingRefreshInterval = defaultSamplingRefreshInterval
- }
- return options
-}
-
-// IsSampled implements IsSampled() of Sampler.
-func (s *RemotelyControlledSampler) IsSampled(id TraceID, operation string) (bool, []Tag) {
- s.RLock()
- defer s.RUnlock()
- return s.sampler.IsSampled(id, operation)
-}
-
-// Close implements Close() of Sampler.
-func (s *RemotelyControlledSampler) Close() {
- if swapped := atomic.CompareAndSwapInt64(&s.closed, 0, 1); !swapped {
- s.logger.Error("Repeated attempt to close the sampler is ignored")
- return
- }
-
- var wg sync.WaitGroup
- wg.Add(1)
- s.doneChan <- &wg
- wg.Wait()
-}
-
-// Equal implements Equal() of Sampler.
-func (s *RemotelyControlledSampler) Equal(other Sampler) bool {
- // NB The Equal() function is expensive and will be removed. See adaptiveSampler.Equal() for
- // more information.
- if o, ok := other.(*RemotelyControlledSampler); ok {
- s.RLock()
- o.RLock()
- defer s.RUnlock()
- defer o.RUnlock()
- return s.sampler.Equal(o.sampler)
- }
- return false
-}
-
-func (s *RemotelyControlledSampler) pollController() {
- ticker := time.NewTicker(s.samplingRefreshInterval)
- defer ticker.Stop()
- s.pollControllerWithTicker(ticker)
-}
-
-func (s *RemotelyControlledSampler) pollControllerWithTicker(ticker *time.Ticker) {
- for {
- select {
- case <-ticker.C:
- s.updateSampler()
- case wg := <-s.doneChan:
- wg.Done()
- return
- }
- }
-}
-
-func (s *RemotelyControlledSampler) getSampler() Sampler {
- s.Lock()
- defer s.Unlock()
- return s.sampler
-}
-
-func (s *RemotelyControlledSampler) setSampler(sampler Sampler) {
- s.Lock()
- defer s.Unlock()
- s.sampler = sampler
-}
-
-func (s *RemotelyControlledSampler) updateSampler() {
- res, err := s.manager.GetSamplingStrategy(s.serviceName)
- if err != nil {
- s.metrics.SamplerQueryFailure.Inc(1)
- s.logger.Infof("Unable to query sampling strategy: %v", err)
- return
- }
- s.Lock()
- defer s.Unlock()
-
- s.metrics.SamplerRetrieved.Inc(1)
- if strategies := res.GetOperationSampling(); strategies != nil {
- s.updateAdaptiveSampler(strategies)
- } else {
- err = s.updateRateLimitingOrProbabilisticSampler(res)
- }
- if err != nil {
- s.metrics.SamplerUpdateFailure.Inc(1)
- s.logger.Infof("Unable to handle sampling strategy response %+v. Got error: %v", res, err)
- return
- }
- s.metrics.SamplerUpdated.Inc(1)
-}
-
-// NB: this function should only be called while holding a Write lock
-func (s *RemotelyControlledSampler) updateAdaptiveSampler(strategies *sampling.PerOperationSamplingStrategies) {
- if adaptiveSampler, ok := s.sampler.(*adaptiveSampler); ok {
- adaptiveSampler.update(strategies)
- } else {
- s.sampler = newAdaptiveSampler(strategies, s.maxOperations)
- }
-}
-
-// NB: this function should only be called while holding a Write lock
-func (s *RemotelyControlledSampler) updateRateLimitingOrProbabilisticSampler(res *sampling.SamplingStrategyResponse) error {
- var newSampler Sampler
- if probabilistic := res.GetProbabilisticSampling(); probabilistic != nil {
- newSampler = newProbabilisticSampler(probabilistic.SamplingRate)
- } else if rateLimiting := res.GetRateLimitingSampling(); rateLimiting != nil {
- newSampler = NewRateLimitingSampler(float64(rateLimiting.MaxTracesPerSecond))
- } else {
- return fmt.Errorf("Unsupported sampling strategy type %v", res.GetStrategyType())
- }
- if !s.sampler.Equal(newSampler) {
- s.sampler = newSampler
- }
- return nil
-}
diff --git a/vendor/github.com/uber/jaeger-client-go/sampler_remote.go b/vendor/github.com/uber/jaeger-client-go/sampler_remote.go
new file mode 100644
index 000000000..9bd0c9822
--- /dev/null
+++ b/vendor/github.com/uber/jaeger-client-go/sampler_remote.go
@@ -0,0 +1,334 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jaeger
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/uber/jaeger-client-go/thrift-gen/sampling"
+)
+
+const (
+ defaultSamplingRefreshInterval = time.Minute
+)
+
+// SamplingStrategyFetcher is used to fetch sampling strategy updates from remote server.
+type SamplingStrategyFetcher interface {
+ Fetch(service string) ([]byte, error)
+}
+
+// SamplingStrategyParser is used to parse sampling strategy updates. The output object
+// should be of the type that is recognized by the SamplerUpdaters.
+type SamplingStrategyParser interface {
+ Parse(response []byte) (interface{}, error)
+}
+
+// SamplerUpdater is used by RemotelyControlledSampler to apply sampling strategies,
+// retrieved from remote config server, to the current sampler. The updater can modify
+// the sampler in-place if sampler supports it, or create a new one.
+//
+// If the strategy does not contain configuration for the sampler in question,
+// updater must return modifiedSampler=nil to give other updaters a chance to inspect
+// the sampling strategy response.
+//
+// RemotelyControlledSampler invokes the updaters while holding a lock on the main sampler.
+type SamplerUpdater interface {
+ Update(sampler SamplerV2, strategy interface{}) (modified SamplerV2, err error)
+}
+
+// RemotelyControlledSampler is a delegating sampler that polls a remote server
+// for the appropriate sampling strategy, constructs a corresponding sampler and
+// delegates to it for sampling decisions.
+type RemotelyControlledSampler struct {
+ // These fields must be first in the struct because `sync/atomic` expects 64-bit alignment.
+ // Cf. https://github.com/uber/jaeger-client-go/issues/155, https://goo.gl/zW7dgq
+ closed int64 // 0 - not closed, 1 - closed
+
+ sync.RWMutex
+ samplerOptions
+
+ serviceName string
+ doneChan chan *sync.WaitGroup
+}
+
+// NewRemotelyControlledSampler creates a sampler that periodically pulls
+// the sampling strategy from an HTTP sampling server (e.g. jaeger-agent).
+func NewRemotelyControlledSampler(
+ serviceName string,
+ opts ...SamplerOption,
+) *RemotelyControlledSampler {
+ options := new(samplerOptions).applyOptionsAndDefaults(opts...)
+ sampler := &RemotelyControlledSampler{
+ samplerOptions: *options,
+ serviceName: serviceName,
+ doneChan: make(chan *sync.WaitGroup),
+ }
+ go sampler.pollController()
+ return sampler
+}
+
+// IsSampled implements IsSampled() of Sampler.
+// TODO (breaking change) remove when Sampler V1 is removed
+func (s *RemotelyControlledSampler) IsSampled(id TraceID, operation string) (bool, []Tag) {
+ return false, nil
+}
+
+// OnCreateSpan implements OnCreateSpan of SamplerV2.
+func (s *RemotelyControlledSampler) OnCreateSpan(span *Span) SamplingDecision {
+ return s.sampler.OnCreateSpan(span)
+}
+
+// OnSetOperationName implements OnSetOperationName of SamplerV2.
+func (s *RemotelyControlledSampler) OnSetOperationName(span *Span, operationName string) SamplingDecision {
+ return s.sampler.OnSetOperationName(span, operationName)
+}
+
+// OnSetTag implements OnSetTag of SamplerV2.
+func (s *RemotelyControlledSampler) OnSetTag(span *Span, key string, value interface{}) SamplingDecision {
+ return s.sampler.OnSetTag(span, key, value)
+}
+
+// OnFinishSpan implements OnFinishSpan of SamplerV2.
+func (s *RemotelyControlledSampler) OnFinishSpan(span *Span) SamplingDecision {
+ return s.sampler.OnFinishSpan(span)
+}
+
+// Close implements Close() of Sampler.
+func (s *RemotelyControlledSampler) Close() {
+ if swapped := atomic.CompareAndSwapInt64(&s.closed, 0, 1); !swapped {
+ s.logger.Error("Repeated attempt to close the sampler is ignored")
+ return
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ s.doneChan <- &wg
+ wg.Wait()
+}
+
+// Equal implements Equal() of Sampler.
+func (s *RemotelyControlledSampler) Equal(other Sampler) bool {
+ // NB The Equal() function is expensive and will be removed. See PerOperationSampler.Equal() for
+ // more information.
+ return false
+}
+
+func (s *RemotelyControlledSampler) pollController() {
+ ticker := time.NewTicker(s.samplingRefreshInterval)
+ defer ticker.Stop()
+ s.pollControllerWithTicker(ticker)
+}
+
+func (s *RemotelyControlledSampler) pollControllerWithTicker(ticker *time.Ticker) {
+ for {
+ select {
+ case <-ticker.C:
+ s.UpdateSampler()
+ case wg := <-s.doneChan:
+ wg.Done()
+ return
+ }
+ }
+}
+
+// Sampler returns the currently active sampler.
+func (s *RemotelyControlledSampler) Sampler() SamplerV2 {
+ s.Lock()
+ defer s.Unlock()
+ return s.sampler
+}
+
+func (s *RemotelyControlledSampler) setSampler(sampler SamplerV2) {
+ s.Lock()
+ defer s.Unlock()
+ s.sampler = sampler
+}
+
+// UpdateSampler forces the sampler to fetch sampling strategy from backend server.
+// This function is called automatically on a timer, but can also be safely called manually, e.g. from tests.
+func (s *RemotelyControlledSampler) UpdateSampler() {
+ res, err := s.samplingFetcher.Fetch(s.serviceName)
+ if err != nil {
+ s.metrics.SamplerQueryFailure.Inc(1)
+ s.logger.Infof("failed to fetch sampling strategy: %v", err)
+ return
+ }
+ strategy, err := s.samplingParser.Parse(res)
+ if err != nil {
+ s.metrics.SamplerUpdateFailure.Inc(1)
+ s.logger.Infof("failed to parse sampling strategy response: %v", err)
+ return
+ }
+
+ s.Lock()
+ defer s.Unlock()
+
+ s.metrics.SamplerRetrieved.Inc(1)
+ if err := s.updateSamplerViaUpdaters(strategy); err != nil {
+ s.metrics.SamplerUpdateFailure.Inc(1)
+ s.logger.Infof("failed to handle sampling strategy response %+v. Got error: %v", res, err)
+ return
+ }
+ s.metrics.SamplerUpdated.Inc(1)
+}
+
+// NB: this function should only be called while holding a Write lock
+func (s *RemotelyControlledSampler) updateSamplerViaUpdaters(strategy interface{}) error {
+ for _, updater := range s.updaters {
+ sampler, err := updater.Update(s.sampler, strategy)
+ if err != nil {
+ return err
+ }
+ if sampler != nil {
+ s.sampler = sampler
+ return nil
+ }
+ }
+ return fmt.Errorf("unsupported sampling strategy %+v", strategy)
+}
+
+// -----------------------
+
+// ProbabilisticSamplerUpdater is used by RemotelyControlledSampler to parse sampling configuration.
+type ProbabilisticSamplerUpdater struct{}
+
+// Update implements Update of SamplerUpdater.
+func (u *ProbabilisticSamplerUpdater) Update(sampler SamplerV2, strategy interface{}) (SamplerV2, error) {
+ type response interface {
+ GetProbabilisticSampling() *sampling.ProbabilisticSamplingStrategy
+ }
+ var _ response = new(sampling.SamplingStrategyResponse) // sanity signature check
+ if resp, ok := strategy.(response); ok {
+ if probabilistic := resp.GetProbabilisticSampling(); probabilistic != nil {
+ if ps, ok := sampler.(*ProbabilisticSampler); ok {
+ if err := ps.Update(probabilistic.SamplingRate); err != nil {
+ return nil, err
+ }
+ return sampler, nil
+ }
+ return newProbabilisticSampler(probabilistic.SamplingRate), nil
+ }
+ }
+ return nil, nil
+}
+
+// -----------------------
+
+// RateLimitingSamplerUpdater is used by RemotelyControlledSampler to parse sampling configuration.
+type RateLimitingSamplerUpdater struct{}
+
+// Update implements Update of SamplerUpdater.
+func (u *RateLimitingSamplerUpdater) Update(sampler SamplerV2, strategy interface{}) (SamplerV2, error) {
+ type response interface {
+ GetRateLimitingSampling() *sampling.RateLimitingSamplingStrategy
+ }
+ var _ response = new(sampling.SamplingStrategyResponse) // sanity signature check
+ if resp, ok := strategy.(response); ok {
+ if rateLimiting := resp.GetRateLimitingSampling(); rateLimiting != nil {
+ rateLimit := float64(rateLimiting.MaxTracesPerSecond)
+ if rl, ok := sampler.(*RateLimitingSampler); ok {
+ rl.Update(rateLimit)
+ return rl, nil
+ }
+ return NewRateLimitingSampler(rateLimit), nil
+ }
+ }
+ return nil, nil
+}
+
+// -----------------------
+
+// AdaptiveSamplerUpdater is used by RemotelyControlledSampler to parse sampling configuration.
+type AdaptiveSamplerUpdater struct {
+ MaxOperations int // required
+ OperationNameLateBinding bool
+}
+
+// Update implements Update of SamplerUpdater.
+func (u *AdaptiveSamplerUpdater) Update(sampler SamplerV2, strategy interface{}) (SamplerV2, error) {
+ type response interface {
+ GetOperationSampling() *sampling.PerOperationSamplingStrategies
+ }
+ var _ response = new(sampling.SamplingStrategyResponse) // sanity signature check
+ if p, ok := strategy.(response); ok {
+ if operations := p.GetOperationSampling(); operations != nil {
+ if as, ok := sampler.(*PerOperationSampler); ok {
+ as.update(operations)
+ return as, nil
+ }
+ return NewPerOperationSampler(PerOperationSamplerParams{
+ MaxOperations: u.MaxOperations,
+ OperationNameLateBinding: u.OperationNameLateBinding,
+ Strategies: operations,
+ }), nil
+ }
+ }
+ return nil, nil
+}
+
+// -----------------------
+
+type httpSamplingStrategyFetcher struct {
+ serverURL string
+ logger Logger
+}
+
+func (f *httpSamplingStrategyFetcher) Fetch(serviceName string) ([]byte, error) {
+ v := url.Values{}
+ v.Set("service", serviceName)
+ uri := f.serverURL + "?" + v.Encode()
+
+ // TODO create and reuse http.Client with proper timeout settings, etc.
+ resp, err := http.Get(uri)
+ if err != nil {
+ return nil, err
+ }
+
+ defer func() {
+ if err := resp.Body.Close(); err != nil {
+ f.logger.Error(fmt.Sprintf("failed to close HTTP response body: %+v", err))
+ }
+ }()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.StatusCode >= 400 {
+ return nil, fmt.Errorf("StatusCode: %d, Body: %s", resp.StatusCode, body)
+ }
+
+ return body, nil
+}
+
+// -----------------------
+
+type samplingStrategyParser struct{}
+
+func (p *samplingStrategyParser) Parse(response []byte) (interface{}, error) {
+ strategy := new(sampling.SamplingStrategyResponse)
+ if err := json.Unmarshal(response, strategy); err != nil {
+ return nil, err
+ }
+ return strategy, nil
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/sampler_options.go b/vendor/github.com/uber/jaeger-client-go/sampler_remote_options.go
index 75d28a561..7a292effc 100644
--- a/vendor/github.com/uber/jaeger-client-go/sampler_options.go
+++ b/vendor/github.com/uber/jaeger-client-go/sampler_remote_options.go
@@ -16,6 +16,8 @@ package jaeger
import (
"time"
+
+ "github.com/uber/jaeger-client-go/log"
)
// SamplerOption is a function that sets some option on the sampler
@@ -27,10 +29,13 @@ var SamplerOptions samplerOptions
type samplerOptions struct {
metrics *Metrics
maxOperations int
- sampler Sampler
+ sampler SamplerV2
logger Logger
samplingServerURL string
samplingRefreshInterval time.Duration
+ samplingFetcher SamplingStrategyFetcher
+ samplingParser SamplingStrategyParser
+ updaters []SamplerUpdater
}
// Metrics creates a SamplerOption that initializes Metrics on the sampler,
@@ -53,7 +58,7 @@ func (samplerOptions) MaxOperations(maxOperations int) SamplerOption {
// to use before a remote sampler is created and used.
func (samplerOptions) InitialSampler(sampler Sampler) SamplerOption {
return func(o *samplerOptions) {
- o.sampler = sampler
+ o.sampler = samplerV1toV2(sampler)
}
}
@@ -79,3 +84,65 @@ func (samplerOptions) SamplingRefreshInterval(samplingRefreshInterval time.Durat
o.samplingRefreshInterval = samplingRefreshInterval
}
}
+
+// SamplingStrategyFetcher creates a SamplerOption that initializes sampling strategy fetcher.
+func (samplerOptions) SamplingStrategyFetcher(fetcher SamplingStrategyFetcher) SamplerOption {
+ return func(o *samplerOptions) {
+ o.samplingFetcher = fetcher
+ }
+}
+
+// SamplingStrategyParser creates a SamplerOption that initializes sampling strategy parser.
+func (samplerOptions) SamplingStrategyParser(parser SamplingStrategyParser) SamplerOption {
+ return func(o *samplerOptions) {
+ o.samplingParser = parser
+ }
+}
+
+// Updaters creates a SamplerOption that initializes sampler updaters.
+func (samplerOptions) Updaters(updaters ...SamplerUpdater) SamplerOption {
+ return func(o *samplerOptions) {
+ o.updaters = updaters
+ }
+}
+
+func (o *samplerOptions) applyOptionsAndDefaults(opts ...SamplerOption) *samplerOptions {
+ for _, option := range opts {
+ option(o)
+ }
+ if o.sampler == nil {
+ o.sampler = newProbabilisticSampler(0.001)
+ }
+ if o.logger == nil {
+ o.logger = log.NullLogger
+ }
+ if o.maxOperations <= 0 {
+ o.maxOperations = defaultMaxOperations
+ }
+ if o.samplingServerURL == "" {
+ o.samplingServerURL = DefaultSamplingServerURL
+ }
+ if o.metrics == nil {
+ o.metrics = NewNullMetrics()
+ }
+ if o.samplingRefreshInterval <= 0 {
+ o.samplingRefreshInterval = defaultSamplingRefreshInterval
+ }
+ if o.samplingFetcher == nil {
+ o.samplingFetcher = &httpSamplingStrategyFetcher{
+ serverURL: o.samplingServerURL,
+ logger: o.logger,
+ }
+ }
+ if o.samplingParser == nil {
+ o.samplingParser = new(samplingStrategyParser)
+ }
+ if o.updaters == nil {
+ o.updaters = []SamplerUpdater{
+ &AdaptiveSamplerUpdater{MaxOperations: o.maxOperations},
+ new(ProbabilisticSamplerUpdater),
+ new(RateLimitingSamplerUpdater),
+ }
+ }
+ return o
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/sampler_v2.go b/vendor/github.com/uber/jaeger-client-go/sampler_v2.go
new file mode 100644
index 000000000..a50671a23
--- /dev/null
+++ b/vendor/github.com/uber/jaeger-client-go/sampler_v2.go
@@ -0,0 +1,93 @@
+// Copyright (c) 2019 Uber Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package jaeger
+
+// SamplingDecision is returned by the V2 samplers.
+type SamplingDecision struct {
+ Sample bool
+ Retryable bool
+ Tags []Tag
+}
+
+// SamplerV2 is an extension of the V1 samplers that allows sampling decisions
+// be made at different points of the span lifecycle.
+type SamplerV2 interface {
+ OnCreateSpan(span *Span) SamplingDecision
+ OnSetOperationName(span *Span, operationName string) SamplingDecision
+ OnSetTag(span *Span, key string, value interface{}) SamplingDecision
+ OnFinishSpan(span *Span) SamplingDecision
+
+ // Close does a clean shutdown of the sampler, stopping any background
+ // go-routines it may have started.
+ Close()
+}
+
+// samplerV1toV2 wraps legacy V1 sampler into an adapter that make it look like V2.
+func samplerV1toV2(s Sampler) SamplerV2 {
+ if s2, ok := s.(SamplerV2); ok {
+ return s2
+ }
+ type legacySamplerV1toV2Adapter struct {
+ legacySamplerV1Base
+ }
+ return &legacySamplerV1toV2Adapter{
+ legacySamplerV1Base: legacySamplerV1Base{
+ delegate: s.IsSampled,
+ },
+ }
+}
+
+// SamplerV2Base can be used by V2 samplers to implement dummy V1 methods.
+// Supporting V1 API is required because Tracer configuration only accepts V1 Sampler
+// for backwards compatibility reasons.
+// TODO (breaking change) remove this in the next major release
+type SamplerV2Base struct{}
+
+// IsSampled implements IsSampled of Sampler.
+func (SamplerV2Base) IsSampled(id TraceID, operation string) (sampled bool, tags []Tag) {
+ return false, nil
+}
+
+// Close implements Close of Sampler.
+func (SamplerV2Base) Close() {}
+
+// Equal implements Equal of Sampler.
+func (SamplerV2Base) Equal(other Sampler) bool { return false }
+
+// legacySamplerV1Base is used as a base for simple samplers that only implement
+// the legacy isSampled() function that is not sensitive to its arguments.
+type legacySamplerV1Base struct {
+ delegate func(id TraceID, operation string) (sampled bool, tags []Tag)
+}
+
+func (s *legacySamplerV1Base) OnCreateSpan(span *Span) SamplingDecision {
+ isSampled, tags := s.delegate(span.context.traceID, span.operationName)
+ return SamplingDecision{Sample: isSampled, Retryable: false, Tags: tags}
+}
+
+func (s *legacySamplerV1Base) OnSetOperationName(span *Span, operationName string) SamplingDecision {
+ isSampled, tags := s.delegate(span.context.traceID, span.operationName)
+ return SamplingDecision{Sample: isSampled, Retryable: false, Tags: tags}
+}
+
+func (s *legacySamplerV1Base) OnSetTag(span *Span, key string, value interface{}) SamplingDecision {
+ return SamplingDecision{Sample: false, Retryable: true}
+}
+
+func (s *legacySamplerV1Base) OnFinishSpan(span *Span) SamplingDecision {
+ return SamplingDecision{Sample: false, Retryable: true}
+}
+
+func (s *legacySamplerV1Base) Close() {}
diff --git a/vendor/github.com/uber/jaeger-client-go/span.go b/vendor/github.com/uber/jaeger-client-go/span.go
index 9df8b6017..bbf6fb068 100644
--- a/vendor/github.com/uber/jaeger-client-go/span.go
+++ b/vendor/github.com/uber/jaeger-client-go/span.go
@@ -34,6 +34,7 @@ type Span struct {
tracer *Tracer
+ // TODO: (breaking change) change to use a pointer
context SpanContext
// The name of the "operation" this span is an instance of.
@@ -65,18 +66,26 @@ type Span struct {
}
// Tag is a simple key value wrapper.
-// TODO deprecate in the next major release, use opentracing.Tag instead.
+// TODO (breaking change) deprecate in the next major release, use opentracing.Tag instead.
type Tag struct {
key string
value interface{}
}
+// NewTag creates a new Tag.
+// TODO (breaking change) deprecate in the next major release, use opentracing.Tag instead.
+func NewTag(key string, value interface{}) Tag {
+ return Tag{key: key, value: value}
+}
+
// SetOperationName sets or changes the operation name.
func (s *Span) SetOperationName(operationName string) opentracing.Span {
s.Lock()
- defer s.Unlock()
- if s.context.IsSampled() {
- s.operationName = operationName
+ s.operationName = operationName
+ s.Unlock()
+ if !s.isSamplingFinalized() {
+ decision := s.tracer.sampler.OnSetOperationName(s, operationName)
+ s.applySamplingDecision(decision, true)
}
s.observer.OnSetOperationName(operationName)
return s
@@ -84,14 +93,24 @@ func (s *Span) SetOperationName(operationName string) opentracing.Span {
// SetTag implements SetTag() of opentracing.Span
func (s *Span) SetTag(key string, value interface{}) opentracing.Span {
+ return s.setTagInternal(key, value, true)
+}
+
+func (s *Span) setTagInternal(key string, value interface{}, lock bool) opentracing.Span {
s.observer.OnSetTag(key, value)
if key == string(ext.SamplingPriority) && !setSamplingPriority(s, value) {
return s
}
- s.Lock()
- defer s.Unlock()
- if s.context.IsSampled() {
- s.setTagNoLocking(key, value)
+ if !s.isSamplingFinalized() {
+ decision := s.tracer.sampler.OnSetTag(s, key, value)
+ s.applySamplingDecision(decision, lock)
+ }
+ if s.isWriteable() {
+ if lock {
+ s.Lock()
+ defer s.Unlock()
+ }
+ s.appendTagNoLocking(key, value)
}
return s
}
@@ -121,14 +140,38 @@ func (s *Span) Duration() time.Duration {
func (s *Span) Tags() opentracing.Tags {
s.Lock()
defer s.Unlock()
- var result = make(opentracing.Tags)
+ var result = make(opentracing.Tags, len(s.tags))
for _, tag := range s.tags {
result[tag.key] = tag.value
}
return result
}
-func (s *Span) setTagNoLocking(key string, value interface{}) {
+// Logs returns micro logs for span
+func (s *Span) Logs() []opentracing.LogRecord {
+ s.Lock()
+ defer s.Unlock()
+
+ return append([]opentracing.LogRecord(nil), s.logs...)
+}
+
+// References returns references for this span
+func (s *Span) References() []opentracing.SpanReference {
+ s.Lock()
+ defer s.Unlock()
+
+ if s.references == nil || len(s.references) == 0 {
+ return nil
+ }
+
+ result := make([]opentracing.SpanReference, len(s.references))
+ for i, r := range s.references {
+ result[i] = opentracing.SpanReference{Type: r.Type, ReferencedContext: r.Context}
+ }
+ return result
+}
+
+func (s *Span) appendTagNoLocking(key string, value interface{}) {
s.tags = append(s.tags, Tag{key: key, value: value})
}
@@ -148,7 +191,7 @@ func (s *Span) logFieldsNoLocking(fields ...log.Field) {
Fields: fields,
Timestamp: time.Now(),
}
- s.appendLog(lr)
+ s.appendLogNoLocking(lr)
}
// LogKV implements opentracing.Span API
@@ -185,12 +228,12 @@ func (s *Span) Log(ld opentracing.LogData) {
if ld.Timestamp.IsZero() {
ld.Timestamp = s.tracer.timeNow()
}
- s.appendLog(ld.ToLogRecord())
+ s.appendLogNoLocking(ld.ToLogRecord())
}
}
// this function should only be called while holding a Write lock
-func (s *Span) appendLog(lr opentracing.LogRecord) {
+func (s *Span) appendLogNoLocking(lr opentracing.LogRecord) {
// TODO add logic to limit number of logs per span (issue #46)
s.logs = append(s.logs, lr)
}
@@ -224,17 +267,25 @@ func (s *Span) FinishWithOptions(options opentracing.FinishOptions) {
}
s.observer.OnFinish(options)
s.Lock()
+ s.duration = options.FinishTime.Sub(s.startTime)
+ s.Unlock()
+ if !s.isSamplingFinalized() {
+ decision := s.tracer.sampler.OnFinishSpan(s)
+ s.applySamplingDecision(decision, true)
+ }
if s.context.IsSampled() {
- s.duration = options.FinishTime.Sub(s.startTime)
- // Note: bulk logs are not subject to maxLogsPerSpan limit
- if options.LogRecords != nil {
- s.logs = append(s.logs, options.LogRecords...)
- }
- for _, ld := range options.BulkLogData {
- s.logs = append(s.logs, ld.ToLogRecord())
+ if len(options.LogRecords) > 0 || len(options.BulkLogData) > 0 {
+ s.Lock()
+ // Note: bulk logs are not subject to maxLogsPerSpan limit
+ if options.LogRecords != nil {
+ s.logs = append(s.logs, options.LogRecords...)
+ }
+ for _, ld := range options.BulkLogData {
+ s.logs = append(s.logs, ld.ToLogRecord())
+ }
+ s.Unlock()
}
}
- s.Unlock()
// call reportSpan even for non-sampled traces, to return span to the pool
// and update metrics counter
s.tracer.reportSpan(s)
@@ -300,23 +351,62 @@ func (s *Span) serviceName() string {
return s.tracer.serviceName
}
+func (s *Span) applySamplingDecision(decision SamplingDecision, lock bool) {
+ if !decision.Retryable {
+ s.context.samplingState.setFinal()
+ }
+ if decision.Sample {
+ s.context.samplingState.setSampled()
+ if len(decision.Tags) > 0 {
+ if lock {
+ s.Lock()
+ defer s.Unlock()
+ }
+ for _, tag := range decision.Tags {
+ s.appendTagNoLocking(tag.key, tag.value)
+ }
+ }
+ }
+}
+
+// Span can be written to if it is sampled or the sampling decision has not been finalized.
+func (s *Span) isWriteable() bool {
+ state := s.context.samplingState
+ return !state.isFinal() || state.isSampled()
+}
+
+func (s *Span) isSamplingFinalized() bool {
+ return s.context.samplingState.isFinal()
+}
+
// setSamplingPriority returns true if the flag was updated successfully, false otherwise.
+// The behavior of setSamplingPriority is surprising
+// If noDebugFlagOnForcedSampling is set
+// setSamplingPriority(span, 1) always sets only flagSampled
+// If noDebugFlagOnForcedSampling is unset, and isDebugAllowed passes
+// setSamplingPriority(span, 1) sets both flagSampled and flagDebug
+// However,
+// setSamplingPriority(span, 0) always only resets flagSampled
+//
+// This means that doing a setSamplingPriority(span, 1) followed by setSamplingPriority(span, 0) can
+// leave flagDebug set
func setSamplingPriority(s *Span, value interface{}) bool {
val, ok := value.(uint16)
if !ok {
return false
}
- s.Lock()
- defer s.Unlock()
if val == 0 {
- s.context.flags = s.context.flags & (^flagSampled)
+ s.context.samplingState.unsetSampled()
+ s.context.samplingState.setFinal()
return true
}
if s.tracer.options.noDebugFlagOnForcedSampling {
- s.context.flags = s.context.flags | flagSampled
+ s.context.samplingState.setSampled()
+ s.context.samplingState.setFinal()
return true
} else if s.tracer.isDebugAllowed(s.operationName) {
- s.context.flags = s.context.flags | flagDebug | flagSampled
+ s.context.samplingState.setDebugAndSampled()
+ s.context.samplingState.setFinal()
return true
}
return false
@@ -326,5 +416,5 @@ func setSamplingPriority(s *Span, value interface{}) bool {
func EnableFirehose(s *Span) {
s.Lock()
defer s.Unlock()
- s.context.flags |= flagFirehose
+ s.context.samplingState.setFirehose()
}
diff --git a/vendor/github.com/uber/jaeger-client-go/context.go b/vendor/github.com/uber/jaeger-client-go/span_context.go
index 43553655a..b7230abfe 100644
--- a/vendor/github.com/uber/jaeger-client-go/context.go
+++ b/vendor/github.com/uber/jaeger-client-go/span_context.go
@@ -19,12 +19,15 @@ import (
"fmt"
"strconv"
"strings"
+ "sync"
+
+ "go.uber.org/atomic"
)
const (
- flagSampled = byte(1)
- flagDebug = byte(2)
- flagFirehose = byte(8)
+ flagSampled = 1
+ flagDebug = 2
+ flagFirehose = 8
)
var (
@@ -56,9 +59,6 @@ type SpanContext struct {
// Should be 0 if the current span is a root span.
parentID SpanID
- // flags is a bitmap containing such bits as 'sampled' and 'debug'.
- flags byte
-
// Distributed Context baggage. The is a snapshot in time.
baggage map[string]string
@@ -67,6 +67,102 @@ type SpanContext struct {
//
// See JaegerDebugHeader in constants.go
debugID string
+
+ // samplingState is shared across all spans
+ samplingState *samplingState
+
+ // remote indicates that span context represents a remote parent
+ remote bool
+}
+
+type samplingState struct {
+ // Span context's state flags that are propagated across processes. Only lower 8 bits are used.
+ // We use an int32 instead of byte to be able to use CAS operations.
+ stateFlags atomic.Int32
+
+ // When state is not final, sampling will be retried on other span write operations,
+ // like SetOperationName / SetTag, and the spans will remain writable.
+ final atomic.Bool
+
+ // localRootSpan stores the SpanID of the first span created in this process for a given trace.
+ localRootSpan SpanID
+
+ // extendedState allows samplers to keep intermediate state.
+ // The keys and values in this map are completely opaque: interface{} -> interface{}.
+ extendedState sync.Map
+}
+
+func (s *samplingState) isLocalRootSpan(id SpanID) bool {
+ return id == s.localRootSpan
+}
+
+func (s *samplingState) setFlag(newFlag int32) {
+ swapped := false
+ for !swapped {
+ old := s.stateFlags.Load()
+ swapped = s.stateFlags.CAS(old, old|newFlag)
+ }
+}
+
+func (s *samplingState) unsetFlag(newFlag int32) {
+ swapped := false
+ for !swapped {
+ old := s.stateFlags.Load()
+ swapped = s.stateFlags.CAS(old, old&^newFlag)
+ }
+}
+
+func (s *samplingState) setSampled() {
+ s.setFlag(flagSampled)
+}
+
+func (s *samplingState) unsetSampled() {
+ s.unsetFlag(flagSampled)
+}
+
+func (s *samplingState) setDebugAndSampled() {
+ s.setFlag(flagDebug | flagSampled)
+}
+
+func (s *samplingState) setFirehose() {
+ s.setFlag(flagFirehose)
+}
+
+func (s *samplingState) setFlags(flags byte) {
+ s.stateFlags.Store(int32(flags))
+}
+
+func (s *samplingState) setFinal() {
+ s.final.Store(true)
+}
+
+func (s *samplingState) flags() byte {
+ return byte(s.stateFlags.Load())
+}
+
+func (s *samplingState) isSampled() bool {
+ return s.stateFlags.Load()&flagSampled == flagSampled
+}
+
+func (s *samplingState) isDebug() bool {
+ return s.stateFlags.Load()&flagDebug == flagDebug
+}
+
+func (s *samplingState) isFirehose() bool {
+ return s.stateFlags.Load()&flagFirehose == flagFirehose
+}
+
+func (s *samplingState) isFinal() bool {
+ return s.final.Load()
+}
+
+func (s *samplingState) extendedStateForKey(key interface{}, initValue func() interface{}) interface{} {
+ if value, ok := s.extendedState.Load(key); ok {
+ return value
+ }
+ value := initValue()
+ value, _ = s.extendedState.LoadOrStore(key, value)
+ return value
}
// ForeachBaggageItem implements ForeachBaggageItem() of opentracing.SpanContext
@@ -81,17 +177,28 @@ func (c SpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
// IsSampled returns whether this trace was chosen for permanent storage
// by the sampling mechanism of the tracer.
func (c SpanContext) IsSampled() bool {
- return (c.flags & flagSampled) == flagSampled
+ return c.samplingState.isSampled()
}
// IsDebug indicates whether sampling was explicitly requested by the service.
func (c SpanContext) IsDebug() bool {
- return (c.flags & flagDebug) == flagDebug
+ return c.samplingState.isDebug()
+}
+
+// IsSamplingFinalized indicates whether the sampling decision has been finalized.
+func (c SpanContext) IsSamplingFinalized() bool {
+ return c.samplingState.isFinal()
}
// IsFirehose indicates whether the firehose flag was set
func (c SpanContext) IsFirehose() bool {
- return (c.flags & flagFirehose) == flagFirehose
+ return c.samplingState.isFirehose()
+}
+
+// ExtendedSamplingState returns the custom state object for a given key. If the value for this key does not exist,
+// it is initialized via initValue function. This state can be used by samplers (e.g. x.PrioritySampler).
+func (c SpanContext) ExtendedSamplingState(key interface{}, initValue func() interface{}) interface{} {
+ return c.samplingState.extendedStateForKey(key, initValue)
}
// IsValid indicates whether this context actually represents a valid trace.
@@ -99,11 +206,16 @@ func (c SpanContext) IsValid() bool {
return c.traceID.IsValid() && c.spanID != 0
}
+// SetFirehose enables firehose mode for this trace.
+func (c SpanContext) SetFirehose() {
+ c.samplingState.setFirehose()
+}
+
func (c SpanContext) String() string {
if c.traceID.High == 0 {
- return fmt.Sprintf("%x:%x:%x:%x", c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.flags)
+ return fmt.Sprintf("%x:%x:%x:%x", c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.samplingState.stateFlags.Load())
}
- return fmt.Sprintf("%x%016x:%x:%x:%x", c.traceID.High, c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.flags)
+ return fmt.Sprintf("%x%016x:%x:%x:%x", c.traceID.High, c.traceID.Low, uint64(c.spanID), uint64(c.parentID), c.samplingState.stateFlags.Load())
}
// ContextFromString reconstructs the Context encoded in a string
@@ -130,7 +242,8 @@ func ContextFromString(value string) (SpanContext, error) {
if err != nil {
return emptyContext, err
}
- context.flags = byte(flags)
+ context.samplingState = &samplingState{}
+ context.samplingState.setFlags(byte(flags))
return context, nil
}
@@ -149,18 +262,24 @@ func (c SpanContext) ParentID() SpanID {
return c.parentID
}
+// Flags returns the bitmap containing such bits as 'sampled' and 'debug'.
+func (c SpanContext) Flags() byte {
+ return c.samplingState.flags()
+}
+
// NewSpanContext creates a new instance of SpanContext
func NewSpanContext(traceID TraceID, spanID, parentID SpanID, sampled bool, baggage map[string]string) SpanContext {
- flags := byte(0)
+ samplingState := &samplingState{}
if sampled {
- flags = flagSampled
+ samplingState.setSampled()
}
+
return SpanContext{
- traceID: traceID,
- spanID: spanID,
- parentID: parentID,
- flags: flags,
- baggage: baggage}
+ traceID: traceID,
+ spanID: spanID,
+ parentID: parentID,
+ samplingState: samplingState,
+ baggage: baggage}
}
// CopyFrom copies data from ctx into this context, including span identity and baggage.
@@ -169,7 +288,7 @@ func (c *SpanContext) CopyFrom(ctx *SpanContext) {
c.traceID = ctx.traceID
c.spanID = ctx.spanID
c.parentID = ctx.parentID
- c.flags = ctx.flags
+ c.samplingState = ctx.samplingState
if l := len(ctx.baggage); l > 0 {
c.baggage = make(map[string]string, l)
for k, v := range ctx.baggage {
@@ -193,7 +312,7 @@ func (c SpanContext) WithBaggageItem(key, value string) SpanContext {
newBaggage[key] = value
}
// Use positional parameters so the compiler will help catch new fields.
- return SpanContext{c.traceID, c.spanID, c.parentID, c.flags, newBaggage, ""}
+ return SpanContext{c.traceID, c.spanID, c.parentID, newBaggage, "", c.samplingState, c.remote}
}
// isDebugIDContainerOnly returns true when the instance of the context is only
diff --git a/vendor/github.com/uber/jaeger-client-go/tracer.go b/vendor/github.com/uber/jaeger-client-go/tracer.go
index 745a0c38a..f03372dc7 100644
--- a/vendor/github.com/uber/jaeger-client-go/tracer.go
+++ b/vendor/github.com/uber/jaeger-client-go/tracer.go
@@ -38,7 +38,7 @@ type Tracer struct {
serviceName string
hostIPv4 uint32 // this is for zipkin endpoint conversion
- sampler Sampler
+ sampler SamplerV2
reporter Reporter
metrics Metrics
logger log.Logger
@@ -74,6 +74,7 @@ type Tracer struct {
// NewTracer creates Tracer implementation that reports tracing to Jaeger.
// The returned io.Closer can be used in shutdown hooks to ensure that the internal
// queue of the Reporter is drained and all buffered spans are submitted to collectors.
+// TODO (breaking change) return *Tracer only, without closer.
func NewTracer(
serviceName string,
sampler Sampler,
@@ -82,7 +83,7 @@ func NewTracer(
) (opentracing.Tracer, io.Closer) {
t := &Tracer{
serviceName: serviceName,
- sampler: sampler,
+ sampler: samplerV1toV2(sampler),
reporter: reporter,
injectors: make(map[interface{}]Injector),
extractors: make(map[interface{}]Extractor),
@@ -261,7 +262,7 @@ func (t *Tracer) startSpanWithOptions(
rpcServer = (v == ext.SpanKindRPCServerEnum || v == string(ext.SpanKindRPCServerEnum))
}
- var samplerTags []Tag
+ var internalTags []Tag
newTrace := false
if !isSelfRef {
if !hasParent || !parent.IsValid() {
@@ -272,13 +273,12 @@ func (t *Tracer) startSpanWithOptions(
}
ctx.spanID = SpanID(ctx.traceID.Low)
ctx.parentID = 0
- ctx.flags = byte(0)
+ ctx.samplingState = &samplingState{
+ localRootSpan: ctx.spanID,
+ }
if hasParent && parent.isDebugIDContainerOnly() && t.isDebugAllowed(operationName) {
- ctx.flags |= (flagSampled | flagDebug)
- samplerTags = []Tag{{key: JaegerDebugHeader, value: parent.debugID}}
- } else if sampled, tags := t.sampler.IsSampled(ctx.traceID, operationName); sampled {
- ctx.flags |= flagSampled
- samplerTags = tags
+ ctx.samplingState.setDebugAndSampled()
+ internalTags = append(internalTags, Tag{key: JaegerDebugHeader, value: parent.debugID})
}
} else {
ctx.traceID = parent.traceID
@@ -290,7 +290,11 @@ func (t *Tracer) startSpanWithOptions(
ctx.spanID = SpanID(t.randomID())
ctx.parentID = parent.spanID
}
- ctx.flags = parent.flags
+ ctx.samplingState = parent.samplingState
+ if parent.remote {
+ ctx.samplingState.setFinal()
+ ctx.samplingState.localRootSpan = ctx.spanID
+ }
}
if hasParent {
// copy baggage items
@@ -305,17 +309,30 @@ func (t *Tracer) startSpanWithOptions(
sp := t.newSpan()
sp.context = ctx
+ sp.tracer = t
+ sp.operationName = operationName
+ sp.startTime = options.StartTime
+ sp.duration = 0
+ sp.references = references
+ sp.firstInProcess = rpcServer || sp.context.parentID == 0
+
+ if !sp.isSamplingFinalized() {
+ decision := t.sampler.OnCreateSpan(sp)
+ sp.applySamplingDecision(decision, false)
+ }
sp.observer = t.observer.OnStartSpan(sp, operationName, options)
- return t.startSpanInternal(
- sp,
- operationName,
- options.StartTime,
- samplerTags,
- options.Tags,
- newTrace,
- rpcServer,
- references,
- )
+
+ if tagsTotalLength := len(options.Tags) + len(internalTags); tagsTotalLength > 0 {
+ if sp.tags == nil || cap(sp.tags) < tagsTotalLength {
+ sp.tags = make([]Tag, 0, tagsTotalLength)
+ }
+ sp.tags = append(sp.tags, internalTags...)
+ for k, v := range options.Tags {
+ sp.setTagInternal(k, v, false)
+ }
+ }
+ t.emitNewSpanMetrics(sp, newTrace)
+ return sp
}
// Inject implements Inject() method of opentracing.Tracer
@@ -340,6 +357,7 @@ func (t *Tracer) Extract(
if err != nil {
return nil, err // ensure returned spanCtx is nil
}
+ spanCtx.remote = true
return spanCtx, nil
}
return nil, opentracing.ErrUnsupportedFormat
@@ -350,10 +368,10 @@ func (t *Tracer) Close() error {
t.reporter.Close()
t.sampler.Close()
if mgr, ok := t.baggageRestrictionManager.(io.Closer); ok {
- mgr.Close()
+ _ = mgr.Close()
}
if throttler, ok := t.debugThrottler.(io.Closer); ok {
- throttler.Close()
+ _ = throttler.Close()
}
return nil
}
@@ -368,6 +386,7 @@ func (t *Tracer) Tags() []opentracing.Tag {
}
// getTag returns the value of specific tag, if not exists, return nil.
+// TODO only used by tests, move there.
func (t *Tracer) getTag(key string) (interface{}, bool) {
for _, tag := range t.tags {
if tag.key == key {
@@ -383,41 +402,21 @@ func (t *Tracer) newSpan() *Span {
return t.spanAllocator.Get()
}
-func (t *Tracer) startSpanInternal(
- sp *Span,
- operationName string,
- startTime time.Time,
- internalTags []Tag,
- tags opentracing.Tags,
- newTrace bool,
- rpcServer bool,
- references []Reference,
-) *Span {
- sp.tracer = t
- sp.operationName = operationName
- sp.startTime = startTime
- sp.duration = 0
- sp.references = references
- sp.firstInProcess = rpcServer || sp.context.parentID == 0
- if len(tags) > 0 || len(internalTags) > 0 {
- sp.tags = make([]Tag, len(internalTags), len(tags)+len(internalTags))
- copy(sp.tags, internalTags)
- for k, v := range tags {
- sp.observer.OnSetTag(k, v)
- if k == string(ext.SamplingPriority) && !setSamplingPriority(sp, v) {
- continue
- }
- sp.setTagNoLocking(k, v)
+// emitNewSpanMetrics generates metrics on the number of started spans and traces.
+// newTrace param: we cannot simply check for parentID==0 because in Zipkin model the
+// server-side RPC span has the exact same trace/span/parent IDs as the
+// calling client-side span, but obviously the server side span is
+// no longer a root span of the trace.
+func (t *Tracer) emitNewSpanMetrics(sp *Span, newTrace bool) {
+ if !sp.isSamplingFinalized() {
+ t.metrics.SpansStartedDelayedSampling.Inc(1)
+ if newTrace {
+ t.metrics.TracesStartedDelayedSampling.Inc(1)
}
- }
- // emit metrics
- if sp.context.IsSampled() {
+ // joining a trace is not possible, because sampling decision inherited from upstream is final
+ } else if sp.context.IsSampled() {
t.metrics.SpansStartedSampled.Inc(1)
if newTrace {
- // We cannot simply check for parentID==0 because in Zipkin model the
- // server-side RPC span has the exact same trace/span/parent IDs as the
- // calling client-side span, but obviously the server side span is
- // no longer a root span of the trace.
t.metrics.TracesStartedSampled.Inc(1)
} else if sp.firstInProcess {
t.metrics.TracesJoinedSampled.Inc(1)
@@ -430,15 +429,20 @@ func (t *Tracer) startSpanInternal(
t.metrics.TracesJoinedNotSampled.Inc(1)
}
}
- return sp
}
func (t *Tracer) reportSpan(sp *Span) {
- t.metrics.SpansFinished.Inc(1)
+ if !sp.isSamplingFinalized() {
+ t.metrics.SpansFinishedDelayedSampling.Inc(1)
+ } else if sp.context.IsSampled() {
+ t.metrics.SpansFinishedSampled.Inc(1)
+ } else {
+ t.metrics.SpansFinishedNotSampled.Inc(1)
+ }
- // Note: if the reporter is processing Span asynchronously need to Retain() it
- // otherwise, in the racing condition will be rewritten span data before it will be sent
- // * To remove object use method span.Release()
+ // Note: if the reporter is processing Span asynchronously then it needs to Retain() the span,
+ // and then Release() it when no longer needed.
+ // Otherwise, the span may be reused for another trace and its data may be overwritten.
if sp.context.IsSampled() {
t.reporter.Report(sp)
}
@@ -466,6 +470,11 @@ func (t *Tracer) isDebugAllowed(operation string) bool {
return t.debugThrottler.IsAllowed(operation)
}
+// Sampler returns the sampler given to the tracer at creation.
+func (t *Tracer) Sampler() SamplerV2 {
+ return t.sampler
+}
+
// SelfRef creates an opentracing compliant SpanReference from a jaeger
// SpanContext. This is a factory function in order to encapsulate jaeger specific
// types.
diff --git a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go
index 1b8db9758..bf2f13165 100644
--- a/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go
+++ b/vendor/github.com/uber/jaeger-client-go/utils/rate_limiter.go
@@ -20,22 +20,15 @@ import (
)
// RateLimiter is a filter used to check if a message that is worth itemCost units is within the rate limits.
+//
+// TODO (breaking change) remove this interface in favor of public struct below
+//
+// Deprecated, use ReconfigurableRateLimiter.
type RateLimiter interface {
CheckCredit(itemCost float64) bool
}
-type rateLimiter struct {
- sync.Mutex
-
- creditsPerSecond float64
- balance float64
- maxBalance float64
- lastTick time.Time
-
- timeNow func() time.Time
-}
-
-// NewRateLimiter creates a new rate limiter based on leaky bucket algorithm, formulated in terms of a
+// ReconfigurableRateLimiter is a rate limiter based on leaky bucket algorithm, formulated in terms of a
// credits balance that is replenished every time CheckCredit() method is called (tick) by the amount proportional
// to the time elapsed since the last tick, up to max of creditsPerSecond. A call to CheckCredit() takes a cost
// of an item we want to pay with the balance. If the balance exceeds the cost of the item, the item is "purchased"
@@ -47,31 +40,73 @@ type rateLimiter struct {
//
// It can also be used to limit the rate of traffic in bytes, by setting creditsPerSecond to desired throughput
// as bytes/second, and calling CheckCredit() with the actual message size.
-func NewRateLimiter(creditsPerSecond, maxBalance float64) RateLimiter {
- return &rateLimiter{
+//
+// TODO (breaking change) rename to RateLimiter once the interface is removed
+type ReconfigurableRateLimiter struct {
+ lock sync.Mutex
+
+ creditsPerSecond float64
+ balance float64
+ maxBalance float64
+ lastTick time.Time
+
+ timeNow func() time.Time
+}
+
+// NewRateLimiter creates a new ReconfigurableRateLimiter.
+func NewRateLimiter(creditsPerSecond, maxBalance float64) *ReconfigurableRateLimiter {
+ return &ReconfigurableRateLimiter{
creditsPerSecond: creditsPerSecond,
balance: maxBalance,
maxBalance: maxBalance,
lastTick: time.Now(),
- timeNow: time.Now}
+ timeNow: time.Now,
+ }
}
-func (b *rateLimiter) CheckCredit(itemCost float64) bool {
- b.Lock()
- defer b.Unlock()
- // calculate how much time passed since the last tick, and update current tick
- currentTime := b.timeNow()
- elapsedTime := currentTime.Sub(b.lastTick)
- b.lastTick = currentTime
- // calculate how much credit have we accumulated since the last tick
- b.balance += elapsedTime.Seconds() * b.creditsPerSecond
- if b.balance > b.maxBalance {
- b.balance = b.maxBalance
- }
+// CheckCredit tries to reduce the current balance by itemCost provided that the current balance
+// is not lest than itemCost.
+func (rl *ReconfigurableRateLimiter) CheckCredit(itemCost float64) bool {
+ rl.lock.Lock()
+ defer rl.lock.Unlock()
+
// if we have enough credits to pay for current item, then reduce balance and allow
- if b.balance >= itemCost {
- b.balance -= itemCost
+ if rl.balance >= itemCost {
+ rl.balance -= itemCost
+ return true
+ }
+ // otherwise check if balance can be increased due to time elapsed, and try again
+ rl.updateBalance()
+ if rl.balance >= itemCost {
+ rl.balance -= itemCost
return true
}
return false
}
+
+// updateBalance recalculates current balance based on time elapsed. Must be called while holding a lock.
+func (rl *ReconfigurableRateLimiter) updateBalance() {
+ // calculate how much time passed since the last tick, and update current tick
+ currentTime := rl.timeNow()
+ elapsedTime := currentTime.Sub(rl.lastTick)
+ rl.lastTick = currentTime
+ // calculate how much credit have we accumulated since the last tick
+ rl.balance += elapsedTime.Seconds() * rl.creditsPerSecond
+ if rl.balance > rl.maxBalance {
+ rl.balance = rl.maxBalance
+ }
+}
+
+// Update changes the main parameters of the rate limiter in-place, while retaining
+// the current accumulated balance (pro-rated to the new maxBalance value). Using this method
+// instead of creating a new rate limiter helps to avoid thundering herd when sampling
+// strategies are updated.
+func (rl *ReconfigurableRateLimiter) Update(creditsPerSecond, maxBalance float64) {
+ rl.lock.Lock()
+ defer rl.lock.Unlock()
+
+ rl.updateBalance() // get up to date balance
+ rl.balance = rl.balance * maxBalance / rl.maxBalance
+ rl.creditsPerSecond = creditsPerSecond
+ rl.maxBalance = maxBalance
+}
diff --git a/vendor/github.com/uber/jaeger-client-go/zipkin.go b/vendor/github.com/uber/jaeger-client-go/zipkin.go
index 636952b7f..98cab4b6e 100644
--- a/vendor/github.com/uber/jaeger-client-go/zipkin.go
+++ b/vendor/github.com/uber/jaeger-client-go/zipkin.go
@@ -55,7 +55,7 @@ func (p *zipkinPropagator) Inject(
carrier.SetTraceID(ctx.TraceID().Low) // TODO this cannot work with 128bit IDs
carrier.SetSpanID(uint64(ctx.SpanID()))
carrier.SetParentID(uint64(ctx.ParentID()))
- carrier.SetFlags(ctx.flags)
+ carrier.SetFlags(ctx.samplingState.flags())
return nil
}
@@ -71,6 +71,7 @@ func (p *zipkinPropagator) Extract(abstractCarrier interface{}) (SpanContext, er
ctx.traceID.Low = carrier.TraceID()
ctx.spanID = SpanID(carrier.SpanID())
ctx.parentID = SpanID(carrier.ParentID())
- ctx.flags = carrier.Flags()
+ ctx.samplingState = &samplingState{}
+ ctx.samplingState.setFlags(carrier.Flags())
return ctx, nil
}
diff --git a/vendor/github.com/ulikunitz/xz/example.go b/vendor/github.com/ulikunitz/xz/example.go
deleted file mode 100644
index 855e60aee..000000000
--- a/vendor/github.com/ulikunitz/xz/example.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014-2017 Ulrich Kunitz. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-package main
-
-import (
- "bytes"
- "io"
- "log"
- "os"
-
- "github.com/ulikunitz/xz"
-)
-
-func main() {
- const text = "The quick brown fox jumps over the lazy dog.\n"
- var buf bytes.Buffer
- // compress text
- w, err := xz.NewWriter(&buf)
- if err != nil {
- log.Fatalf("xz.NewWriter error %s", err)
- }
- if _, err := io.WriteString(w, text); err != nil {
- log.Fatalf("WriteString error %s", err)
- }
- if err := w.Close(); err != nil {
- log.Fatalf("w.Close error %s", err)
- }
- // decompress buffer and write output to stdout
- r, err := xz.NewReader(&buf)
- if err != nil {
- log.Fatalf("NewReader error %s", err)
- }
- if _, err = io.Copy(os.Stdout, r); err != nil {
- log.Fatalf("io.Copy error %s", err)
- }
-}