diff --git a/go.mod b/go.mod index 7d108dc..1863ebf 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,12 @@ require ( github.com/coreos/bbolt v1.3.2 // indirect github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e // indirect github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/dgraph-io/ristretto v0.0.3 github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/fsnotify/fsnotify v1.4.7 github.com/gogo/protobuf v1.2.1 // indirect - github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/protobuf v1.3.3 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect @@ -27,7 +29,7 @@ require ( github.com/spf13/cast v1.3.0 github.com/spf13/jwalterweatherman v1.0.0 github.com/spf13/pflag v1.0.3 - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.4.0 github.com/subosito/gotenv v1.2.0 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect diff --git a/go.sum b/go.sum index 463aa7d..ed827f8 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,7 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -33,6 +34,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c h1:+0HFd5KSZ/mm3JmhmrDukiId5iR6w4+BdFtfSy4yWIc= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= @@ -48,8 +50,12 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= @@ -66,16 +72,16 @@ github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -181,7 +187,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -214,6 +219,7 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -225,10 +231,10 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= @@ -248,7 +254,6 @@ go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= @@ -304,7 +309,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -313,7 +317,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -328,7 +331,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -352,7 +354,6 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -368,7 +369,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -378,6 +378,7 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/stub/benchmark.json b/stub/benchmark.json new file mode 100644 index 0000000..d082104 --- /dev/null +++ b/stub/benchmark.json @@ -0,0 +1,248 @@ +{ + "log": { + "level": "debug", + "format": "json" + }, + "profiling": "cpu", + "serve": { + "proxy": { + "port": 1234, + "host": "127.0.0.1", + "timeout": { + "read": "1s", + "write": "2s", + "idle": "3s" + }, + "cors": { + "enabled": true, + "allowed_origins": [ + "https://example.com", + "https://*.example.com" + ], + "allowed_methods": [ + "POST", + "GET", + "PUT", + "PATCH", + "DELETE" + ], + "allowed_headers": [ + "Authorization", + "Content-Type" + ], + "exposed_headers": [ + "Content-Type" + ], + "allow_credentials": true, + "max_age": 10, + "debug": true + }, + "tls": { + "key": { + "path": "/path/to/key.pem", + "base64": "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLVxuTUlJRkRqQkFCZ2txaGtpRzl3MEJCUTB3..." + }, + "cert": { + "path": "/path/to/cert.pem", + "base64": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5NSUlEWlRDQ0FrMmdBd0lCQWdJRVY1eE90REFOQmdr..." + } + } + }, + "api": { + "port": 1235, + "host": "127.0.0.2", + "cors": { + "enabled": true, + "allowed_origins": [ + "https://example.org", + "https://*.example.org" + ], + "allowed_methods": [ + "GET", + "PUT", + "PATCH", + "DELETE" + ], + "allowed_headers": [ + "Authorization", + "Content-Type" + ], + "exposed_headers": [ + "Content-Type" + ], + "allow_credentials": true, + "max_age": 10, + "debug": true + }, + "tls": { + "key": { + "path": "/path/to/key.pem", + "base64": "LS0tLS1CRUdJTiBFTkNSWVBURUQgUFJJVkFURSBLRVktLS0tLVxuTUlJRkRqQkFCZ2txaGtpRzl3MEJCUTB3..." + }, + "cert": { + "path": "/path/to/cert.pem", + "base64": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5NSUlEWlRDQ0FrMmdBd0lCQWdJRVY1eE90REFOQmdr..." + } + } + } + }, + "access_rules": { + "repositories": [ + "file://path/to/rules.json", + "inline://W3siaWQiOiJmb28tcnVsZSIsImF1dGhlbnRpY2F0b3JzIjpbXX1d", + "https://path-to-my-rules/rules.json" + ], + "matching_strategy": "glob" + }, + "errors": { + "fallback": [ + "json" + ], + "handlers": { + "redirect": { + "enabled": true, + "config": { + "to": "http://path-to/redirect" + } + }, + "json": { + "enabled": true, + "config": { + "verbose": true, + "when": [ + { + "error": [ + "unauthorized", + "forbidden", + "internal_server_error" + ], + "request": { + "header": { + "content_type": [ + "application/json" + ], + "accept": [ + "application/json" + ] + }, + "cidr": [ + "127.0.0.0/24" + ] + } + } + ] + } + } + } + }, + "authenticators": { + "anonymous": { + "enabled": true, + "config": { + "subject": "guest" + } + }, + "cookie_session": { + "enabled": true, + "config": { + "check_session_url": "https://session-store-host", + "only": [ + "sessionid" + ] + } + }, + "jwt": { + "enabled": true, + "config": { + "jwks_urls": [ + "https://my-website.com/.well-known/jwks.json", + "https://my-other-website.com/.well-known/jwks.json", + "file://path/to/local/jwks.json" + ], + "scope_strategy": "wildcard" + } + }, + "noop": { + "enabled": true + }, + "oauth2_client_credentials": { + "enabled": true, + "config": { + "token_url": "https://my-website.com/oauth2/token" + } + }, + "oauth2_introspection": { + "enabled": true, + "config": { + "introspection_url": "https://my-website.com/oauth2/introspection", + "scope_strategy": "exact", + "pre_authorization": { + "enabled": true, + "client_id": "some_id", + "client_secret": "some_secret", + "scope": [ + "foo", + "bar" + ], + "token_url": "https://my-website.com/oauth2/token" + } + } + }, + "unauthorized": { + "enabled": true + } + }, + "authorizers": { + "allow": { + "enabled": true + }, + "deny": { + "enabled": true + }, + "keto_engine_acp_ory": { + "enabled": true, + "config": { + "base_url": "http://my-keto/", + "required_action": "unknown", + "required_resource": "unknown" + } + } + }, + "mutators": { + "header": { + "enabled": false, + "config": { + "headers": { + "foo": "bar" + } + } + }, + "cookie": { + "enabled": true, + "config": { + "cookies": { + "foo": "bar" + } + } + }, + "hydrator": { + "enabled": true, + "config": { + "api": { + "url": "https://some-url/" + } + } + }, + "id_token": { + "enabled": true, + "config": { + "issuer_url": "https://my-oathkeeper/", + "jwks_url": "https://fetch-keys/from/this/location.json", + "ttl": "1h" + } + }, + "noop": { + "enabled": true + } + } +} diff --git a/viper.go b/viper.go index c3130c2..c562ab6 100644 --- a/viper.go +++ b/viper.go @@ -34,6 +34,7 @@ import ( "sync" "time" + "github.com/dgraph-io/ristretto" "github.com/fsnotify/fsnotify" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/printer" @@ -214,6 +215,8 @@ type Viper struct { properties *properties.Properties onConfigChange func(fsnotify.Event) + + cache *ristretto.Cache } // New returns an initialized Viper instance. @@ -231,7 +234,6 @@ func New() *Viper { v.env = make(map[string]string) v.aliases = make(map[string]string) v.typeByDefValue = false - return v } @@ -270,6 +272,15 @@ func EnvKeyReplacer(r StringReplacer) Option { }) } +// Cache sets Viper's cache (*ristretto.Cache). +// Using a cache may cause updates to external sources after the value is cached to be ignored, +// e.g. updating a flag value after the key was initially retrieve does not update the cached value. +func Cache(c *ristretto.Cache) Option { + return optionFunc(func(v *Viper) { + v.cache = c + }) +} + // NewWithOptions creates a new Viper instance. func NewWithOptions(opts ...Option) *Viper { v := New() @@ -422,6 +433,7 @@ func (v *Viper) SetConfigFile(in string) { func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } func (v *Viper) SetEnvPrefix(in string) { + v.cache.Clear() if in != "" { v.envPrefix = in } @@ -441,6 +453,7 @@ func (v *Viper) mergeWithEnvPrefix(in string) string { func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) } func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) { + v.cache.Clear() v.allowEmptyEnv = allowEmptyEnv } @@ -470,6 +483,7 @@ func (v *Viper) ConfigFileUsed() string { return v.configFile } func AddConfigPath(in string) { v.AddConfigPath(in) } func (v *Viper) AddConfigPath(in string) { + v.cache.Clear() if in != "" { absin := absPathify(in) jww.INFO.Println("adding", absin, "to paths to search") @@ -492,6 +506,7 @@ func AddRemoteProvider(provider, endpoint, path string) error { } func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { + v.cache.Clear() if !stringInSlice(provider, SupportedRemoteProviders) { return UnsupportedRemoteProviderError(provider) } @@ -524,6 +539,7 @@ func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) err } func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { + v.cache.Clear() if !stringInSlice(provider, SupportedRemoteProviders) { return UnsupportedRemoteProviderError(provider) } @@ -713,6 +729,7 @@ func (v *Viper) isPathShadowedInAutoEnv(path []string) string { func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } func (v *Viper) SetTypeByDefaultValue(enable bool) { + v.cache.Clear() v.typeByDefValue = enable } @@ -732,7 +749,8 @@ func Get(key string) interface{} { return v.Get(key) } func (v *Viper) Get(key string) interface{} { lcaseKey := strings.ToLower(key) - val := v.find(lcaseKey, true) + + val := v.cachedFind(lcaseKey, true) if val == nil { return nil } @@ -748,7 +766,7 @@ func (v *Viper) Get(key string) interface{} { switch valType.(type) { case bool: - return cast.ToBool(val) + val = cast.ToBool(val) case string: return cast.ToString(val) case int32, int16, int8, int: @@ -980,6 +998,7 @@ func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) } func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { + v.cache.Clear() return v.BindFlagValues(pflagValueSet{flags}) } @@ -992,6 +1011,7 @@ func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) } func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { + v.cache.Clear() return v.BindFlagValue(key, pflagValue{flag}) } @@ -1000,6 +1020,7 @@ func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) } func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { + v.cache.Clear() flags.VisitAll(func(flag FlagValue) { if err = v.BindFlagValue(flag.Name(), flag); err != nil { return @@ -1012,6 +1033,7 @@ func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) } func (v *Viper) BindFlagValue(key string, flag FlagValue) error { + v.cache.Clear() if flag == nil { return fmt.Errorf("flag for %q is nil", key) } @@ -1026,6 +1048,7 @@ func (v *Viper) BindFlagValue(key string, flag FlagValue) error { func BindEnv(input ...string) error { return v.BindEnv(input...) } func (v *Viper) BindEnv(input ...string) error { + v.cache.Clear() var key, envkey string if len(input) == 0 { return fmt.Errorf("missing key to bind to") @@ -1044,6 +1067,19 @@ func (v *Viper) BindEnv(input ...string) error { return nil } +// cachedFind uses Viper's cache to find a key's value and `v.find` if it is not available +// in the cache. +func (v *Viper) cachedFind(lcaseKey string, flagDefault bool) interface{} { + realKey := v.realKey(lcaseKey) + if value, found := v.cache.Get(realKey); found { + return value + } + + value := v.find(lcaseKey, flagDefault) + v.cache.Set(realKey, value, 0) + return value +} + // Given a key, find the value. // // Viper will check to see if an alias exists first. @@ -1226,7 +1262,7 @@ func IsSet(key string) bool { return v.IsSet(key) } func (v *Viper) IsSet(key string) bool { lcaseKey := strings.ToLower(key) - val := v.find(lcaseKey, false) + val := v.cachedFind(lcaseKey, false) return val != nil } @@ -1235,6 +1271,7 @@ func (v *Viper) IsSet(key string) bool { func AutomaticEnv() { v.AutomaticEnv() } func (v *Viper) AutomaticEnv() { + v.cache.Clear() v.automaticEnvApplied = true } @@ -1244,6 +1281,7 @@ func (v *Viper) AutomaticEnv() { func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { + v.cache.Clear() v.envKeyReplacer = r } @@ -1313,6 +1351,9 @@ func (v *Viper) InConfig(key string) bool { func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } func (v *Viper) SetDefault(key string, value interface{}) { + // We're clearing the whole cache because nested keys may cause issues if only the key is evicted. + v.cache.Clear() + // If alias passed in, then set the proper default key = v.realKey(strings.ToLower(key)) value = toCaseInsensitiveValue(value) @@ -1332,6 +1373,9 @@ func (v *Viper) SetDefault(key string, value interface{}) { func Set(key string, value interface{}) { v.Set(key, value) } func (v *Viper) Set(key string, value interface{}) { + // We're clearing the whole cache because nested keys may cause issues if only the key is evicted. + v.cache.Clear() + // If alias passed in, then set the proper override key = v.realKey(strings.ToLower(key)) value = toCaseInsensitiveValue(value) @@ -1349,6 +1393,7 @@ func (v *Viper) Set(key string, value interface{}) { func ReadInConfig() error { return v.ReadInConfig() } func (v *Viper) ReadInConfig() error { + v.cache.Clear() jww.INFO.Println("Attempting to read in config file") filename, err := v.getConfigFile() if err != nil { @@ -1380,6 +1425,7 @@ func (v *Viper) ReadInConfig() error { func MergeInConfig() error { return v.MergeInConfig() } func (v *Viper) MergeInConfig() error { + v.cache.Clear() jww.INFO.Println("Attempting to merge in config file") filename, err := v.getConfigFile() if err != nil { @@ -1403,6 +1449,7 @@ func (v *Viper) MergeInConfig() error { func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } func (v *Viper) ReadConfig(in io.Reader) error { + v.cache.Clear() v.config = make(map[string]interface{}) return v.unmarshalReader(in, v.config) } @@ -1411,6 +1458,7 @@ func (v *Viper) ReadConfig(in io.Reader) error { func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } func (v *Viper) MergeConfig(in io.Reader) error { + v.cache.Clear() cfg := make(map[string]interface{}) if err := v.unmarshalReader(in, cfg); err != nil { return err @@ -1423,6 +1471,7 @@ func (v *Viper) MergeConfig(in io.Reader) error { func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) } func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error { + v.cache.Clear() if v.config == nil { v.config = make(map[string]interface{}) } @@ -1978,6 +2027,7 @@ func (v *Viper) AllSettings() map[string]interface{} { func SetFs(fs afero.Fs) { v.SetFs(fs) } func (v *Viper) SetFs(fs afero.Fs) { + v.cache.Clear() v.fs = fs } @@ -1986,6 +2036,7 @@ func (v *Viper) SetFs(fs afero.Fs) { func SetConfigName(in string) { v.SetConfigName(in) } func (v *Viper) SetConfigName(in string) { + v.cache.Clear() if in != "" { v.configName = in v.configFile = "" @@ -1997,6 +2048,7 @@ func (v *Viper) SetConfigName(in string) { func SetConfigType(in string) { v.SetConfigType(in) } func (v *Viper) SetConfigType(in string) { + v.cache.Clear() if in != "" { v.configType = in } diff --git a/viper_test.go b/viper_test.go index 09d5021..b0ee92f 100644 --- a/viper_test.go +++ b/viper_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "github.com/dgraph-io/ristretto" "github.com/fsnotify/fsnotify" "github.com/mitchellh/mapstructure" "github.com/spf13/afero" @@ -244,13 +245,16 @@ func initDirs(t *testing.T) (string, string, func()) { testDirs = append(testDirs, `d\d`) } + wd, err := os.Getwd() + require.NoError(t, err, "Unable to get working directory") + root, err := ioutil.TempDir("", "") require.NoError(t, err, "Failed to create temporary directory") cleanup := true defer func() { if cleanup { - os.Chdir("..") + os.Chdir(wd) os.RemoveAll(root) } }() @@ -273,7 +277,7 @@ func initDirs(t *testing.T) (string, string, func()) { cleanup = false return root, config, func() { - os.Chdir("..") + os.Chdir(wd) os.RemoveAll(root) } } @@ -2270,6 +2274,60 @@ func BenchmarkGetBool(b *testing.B) { } } +func BenchmarkFindCacheDisabled(b *testing.B) { + os.Setenv("MUTATORS_HEADER_ENABLED", "true") + + v = New() + v.SetConfigFile("stub/benchmark.json") + if err := v.ReadInConfig(); err != nil { + b.Fatal(err) + } + + v.AutomaticEnv() + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + keys := v.AllKeys() + numKeys := len(keys) + var key string + for i := 0; i < b.N; i++ { + key = keys[i%numKeys] + if v.find(key, true) == nil { + b.Fatalf("cachedFind returned a nil value for key: %s", key) + } + } +} + +func BenchmarkFindCacheEnabled(b *testing.B) { + os.Setenv("MUTATORS_HEADER_ENABLED", "true") + + cache, err := ristretto.NewCache(&ristretto.Config{ + NumCounters: 1000, + MaxCost: 1 << 20, // 1MB max cache + BufferItems: 64, + }) + require.NoError(b, err) + + v = NewWithOptions(Cache(cache)) + v.SetConfigFile("stub/benchmark.json") + if err := v.ReadInConfig(); err != nil { + b.Fatal(err) + } + + v.AutomaticEnv() + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + + keys := v.AllKeys() + numKeys := len(keys) + + var key string + for i := 0; i < b.N; i++ { + key = keys[i%numKeys] + if v.cachedFind(key, true) == nil { + b.Fatalf("cachedFind returned a nil value for key: %s", key) + } + } +} + func BenchmarkGet(b *testing.B) { key := "BenchmarkGet" v = New()