TUN-7066: Bump coredns to v1.10.0

closes #857
This commit is contained in:
Devin Carr 2023-01-10 16:12:59 -08:00
parent 513855df5c
commit 207f4e2c8d
288 changed files with 10199 additions and 10941 deletions

31
go.mod
View File

@ -5,7 +5,7 @@ go 1.19
require ( require (
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93 github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
github.com/coredns/coredns v1.8.7 github.com/coredns/coredns v1.10.0
github.com/coreos/go-oidc/v3 v3.4.0 github.com/coreos/go-oidc/v3 v3.4.0
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434 github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
@ -20,13 +20,13 @@ require (
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/lucas-clemente/quic-go v0.28.1 github.com/lucas-clemente/quic-go v0.28.1
github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-colorable v0.1.13
github.com/miekg/dns v1.1.45 github.com/miekg/dns v1.1.50
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_golang v1.13.0
github.com/prometheus/client_model v0.2.0 github.com/prometheus/client_model v0.2.0
github.com/rs/zerolog v1.20.0 github.com/rs/zerolog v1.20.0
github.com/stretchr/testify v1.7.1 github.com/stretchr/testify v1.8.1
github.com/urfave/cli/v2 v2.3.0 github.com/urfave/cli/v2 v2.3.0
go.opentelemetry.io/contrib/propagators v0.22.0 go.opentelemetry.io/contrib/propagators v0.22.0
go.opentelemetry.io/otel v1.6.3 go.opentelemetry.io/otel v1.6.3
@ -35,11 +35,11 @@ require (
go.opentelemetry.io/otel/trace v1.6.3 go.opentelemetry.io/otel/trace v1.6.3
go.opentelemetry.io/proto/otlp v0.15.0 go.opentelemetry.io/proto/otlp v0.15.0
go.uber.org/automaxprocs v1.4.0 go.uber.org/automaxprocs v1.4.0
golang.org/x/crypto v0.2.0 golang.org/x/crypto v0.5.0
golang.org/x/net v0.4.0 golang.org/x/net v0.5.0
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
golang.org/x/sys v0.3.0 golang.org/x/sys v0.4.0
golang.org/x/term v0.3.0 golang.org/x/term v0.4.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
gopkg.in/coreos/go-oidc.v2 v2.2.1 gopkg.in/coreos/go-oidc.v2 v2.2.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0
@ -72,6 +72,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
@ -83,19 +84,21 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nxadm/tail v1.4.8 // indirect github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.23.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/procfs v0.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect golang.org/x/oauth2 v0.4.0 // indirect
golang.org/x/text v0.5.0 // indirect golang.org/x/text v0.6.0 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.1.12 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 // indirect google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd // indirect
google.golang.org/grpc v1.47.0 // indirect google.golang.org/grpc v1.51.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )

241
go.sum
View File

@ -61,38 +61,11 @@ dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBr
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/Azure/azure-sdk-for-go v61.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest v0.11.19/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest v0.11.23/go.mod h1:BAWYUWGPEtKPzjVkp0Q6an0MJcJDsoh5Z1BFAEFs4Xs=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
github.com/Azure/go-autorest/autorest/azure/auth v0.5.10/go.mod h1:zQXYYNX9kXzRMrJNVXWUfNy38oPMF5/2TeZ4Wylc9fE=
github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v4.4.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/gostackparse v0.5.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
github.com/DataDog/sketches-go v1.0.0/go.mod h1:O+XkJHWk9w4hDwY2ZUDU31ZC9sNYlYo8DiFsxjYeo1k=
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -102,8 +75,6 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYU
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU=
github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.42.30/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -148,16 +119,14 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0=
github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4=
github.com/coredns/coredns v1.8.7 h1:wVMjAnyFnY7Mc18AFO+9qbGD6ODPtdVUIlzoWrHr3hk= github.com/coredns/coredns v1.10.0 h1:jCfuWsBjTs0dapkkhISfPCzn5LqvSRtrFtaf/Tjj4DI=
github.com/coredns/coredns v1.8.7/go.mod h1:bFmbgEfeRz5aizL2VsQ5LRlsvJuXWkgG/MWG9zxqjVM= github.com/coredns/coredns v1.10.0/go.mod h1:CIfRU5TgpuoIiJBJ4XrofQzfFQpPFh32ERpUevrSlaw=
github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g= github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@ -165,18 +134,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
github.com/dnstap/golang-dnstap v0.4.0/go.mod h1:FqsSdH58NAmkAvKcpyxht7i4FoBjKu8E4JUPt8ipSUs=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -187,7 +145,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 h1:wWke/RUCl7VRjQhwPlR/v0glZXNYzBHdNUzf/Am2Nmg= github.com/facebookgo/freeport v0.0.0-20150612182905-d4adf43b75b9 h1:wWke/RUCl7VRjQhwPlR/v0glZXNYzBHdNUzf/Am2Nmg=
@ -198,18 +155,12 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
github.com/farsightsec/golang-framestream v0.3.0/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/getsentry/sentry-go v0.16.0 h1:owk+S+5XcgJLlGR/3+3s6N4d+uKwqYvh/eS0AIMjPWo= github.com/getsentry/sentry-go v0.16.0 h1:owk+S+5XcgJLlGR/3+3s6N4d+uKwqYvh/eS0AIMjPWo=
@ -224,21 +175,16 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@ -248,21 +194,15 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4= github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU= github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@ -292,12 +232,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -316,8 +253,6 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@ -335,7 +270,6 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210423192551-a2663126120b/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@ -354,46 +288,25 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/infobloxopen/go-trees v0.0.0-20200715205103-96a057b8dfb9/go.mod h1:BaIJzjD2ZnHmx2acPF6XfGLPzNCMiBbMRqJr+8/8uRI=
github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d h1:PRDnysJ9dF1vUMmEzBu6aHQeUluSQy4eWH3RsSSy/vI= github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d h1:PRDnysJ9dF1vUMmEzBu6aHQeUluSQy4eWH3RsSSy/vI=
github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -404,14 +317,11 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -422,10 +332,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
@ -438,13 +345,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -452,53 +356,34 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ=
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ= github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU= github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
@ -508,8 +393,9 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -519,18 +405,17 @@ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7q
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -567,42 +452,32 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ= github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@ -627,11 +502,8 @@ go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5f
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0 h1:h0bKrvdrT/9sBwEJ6iWUqT/N/xPcS66bL4u3isneJ6w= go.opentelemetry.io/proto/otlp v0.15.0 h1:h0bKrvdrT/9sBwEJ6iWUqT/N/xPcS66bL4u3isneJ6w=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0= go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q= go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -643,14 +515,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -707,8 +574,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -736,10 +601,7 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@ -748,8 +610,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -772,8 +634,9 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -805,13 +668,10 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -843,7 +703,6 @@ golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -855,7 +714,6 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -873,13 +731,12 @@ golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -889,13 +746,12 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -919,7 +775,6 @@ golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@ -934,11 +789,9 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@ -948,7 +801,6 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@ -999,7 +851,6 @@ google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
@ -1053,7 +904,6 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@ -1084,7 +934,6 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
@ -1101,16 +950,15 @@ google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 h1:4SPz2GL2CXJt28MTF8V6Ap/9ZiVbQlJeGSd9qtA7DLs=
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd h1:OjndDrsik+Gt+e6fs45z9AxiewiKyLKYpA45W5Kpkks=
google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@ -1134,15 +982,14 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -1160,12 +1007,10 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/DataDog/dd-trace-go.v1 v1.34.0/go.mod h1:HtrC65fyJ6lWazShCC9rlOeiTSZJ0XtZhkwjZM2WpC4=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/coreos/go-oidc.v2 v2.2.1 h1:MY5SZClJ7vhjKfr64a4nHAOV/c3WH2gB9BMrR64J1Mc= gopkg.in/coreos/go-oidc.v2 v2.2.1 h1:MY5SZClJ7vhjKfr64a4nHAOV/c3WH2gB9BMrR64J1Mc=
@ -1184,7 +1029,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@ -1199,24 +1043,9 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
zombiezen.com/go/capnproto2 v2.18.0+incompatible h1:mwfXZniffG5mXokQGHUJWGnqIBggoPfT/CEwon9Yess= zombiezen.com/go/capnproto2 v2.18.0+incompatible h1:mwfXZniffG5mXokQGHUJWGnqIBggoPfT/CEwon9Yess=

View File

@ -35,7 +35,7 @@ func (p MetricsPlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dn
// Update built-in metrics // Update built-in metrics
server := metrics.WithServer(ctx) server := metrics.WithServer(ctx)
vars.Report(server, state, ".", rcode.ToString(rw.Rcode), pluginName, rw.Len, rw.Start) vars.Report(server, state, ".", "", rcode.ToString(rw.Rcode), pluginName, rw.Len, rw.Start)
return status, err return status, err
} }

View File

@ -49,12 +49,23 @@ func newOverlapZone() *zoneOverlap {
// registerAndCheck adds a new zoneAddr for validation, it returns information about existing or overlapping with already registered // registerAndCheck adds a new zoneAddr for validation, it returns information about existing or overlapping with already registered
// we consider that an unbound address is overlapping all bound addresses for same zone, same port // we consider that an unbound address is overlapping all bound addresses for same zone, same port
func (zo *zoneOverlap) registerAndCheck(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) { func (zo *zoneOverlap) registerAndCheck(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
existingZone, overlappingZone = zo.check(z)
if existingZone != nil || overlappingZone != nil {
return existingZone, overlappingZone
}
// there is no overlap, keep the current zoneAddr for future checks
zo.registeredAddr[z] = z
zo.unboundOverlap[z.unbound()] = z
return nil, nil
}
// check validates a zoneAddr for overlap without registering it
func (zo *zoneOverlap) check(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
if exist, ok := zo.registeredAddr[z]; ok { if exist, ok := zo.registeredAddr[z]; ok {
// exact same zone already registered // exact same zone already registered
return &exist, nil return &exist, nil
} }
uz := zoneAddr{Zone: z.Zone, Address: "", Port: z.Port, Transport: z.Transport} uz := z.unbound()
if already, ok := zo.unboundOverlap[uz]; ok { if already, ok := zo.unboundOverlap[uz]; ok {
if z.Address == "" { if z.Address == "" {
// current is not bound to an address, but there is already another zone with a bind address registered // current is not bound to an address, but there is already another zone with a bind address registered
@ -65,8 +76,11 @@ func (zo *zoneOverlap) registerAndCheck(z zoneAddr) (existingZone *zoneAddr, ove
return nil, &uz return nil, &uz
} }
} }
// there is no overlap, keep the current zoneAddr for future checks // there is no overlap
zo.registeredAddr[z] = z
zo.unboundOverlap[uz] = z
return nil, nil return nil, nil
} }
// unbound returns an unbound version of the zoneAddr
func (z zoneAddr) unbound() zoneAddr {
return zoneAddr{Zone: z.Zone, Address: "", Port: z.Port, Transport: z.Transport}
}

View File

@ -1,12 +1,14 @@
package dnsserver package dnsserver
import ( import (
"context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"net/http" "net/http"
"github.com/coredns/caddy" "github.com/coredns/caddy"
"github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/request"
) )
// Config configuration for a single server. // Config configuration for a single server.
@ -28,6 +30,9 @@ type Config struct {
// Debug controls the panic/recover mechanism that is enabled by default. // Debug controls the panic/recover mechanism that is enabled by default.
Debug bool Debug bool
// Stacktrace controls including stacktrace as part of log from recover mechanism, it is disabled by default.
Stacktrace bool
// The transport we implement, normally just "dns" over TCP/UDP, but could be // The transport we implement, normally just "dns" over TCP/UDP, but could be
// DNS-over-TLS or DNS-over-gRPC. // DNS-over-TLS or DNS-over-gRPC.
Transport string Transport string
@ -37,9 +42,20 @@ type Config struct {
// may depend on it. // may depend on it.
HTTPRequestValidateFunc func(*http.Request) bool HTTPRequestValidateFunc func(*http.Request) bool
// FilterFuncs is used to further filter access
// to this handler. E.g. to limit access to a reverse zone
// on a non-octet boundary, i.e. /17
FilterFuncs []FilterFunc
// ViewName is the name of the Viewer PLugin defined in the Config
ViewName string
// TLSConfig when listening for encrypted connections (gRPC, DNS-over-TLS). // TLSConfig when listening for encrypted connections (gRPC, DNS-over-TLS).
TLSConfig *tls.Config TLSConfig *tls.Config
// TSIG secrets, [name]key.
TsigSecret map[string]string
// Plugin stack. // Plugin stack.
Plugin []plugin.Plugin Plugin []plugin.Plugin
@ -54,8 +70,14 @@ type Config struct {
// firstConfigInBlock is used to reference the first config in a server block, for the // firstConfigInBlock is used to reference the first config in a server block, for the
// purpose of sharing single instance of each plugin among all zones in a server block. // purpose of sharing single instance of each plugin among all zones in a server block.
firstConfigInBlock *Config firstConfigInBlock *Config
// metaCollector references the first MetadataCollector plugin, if one exists
metaCollector MetadataCollector
} }
// FilterFunc is a function that filters requests from the Config
type FilterFunc func(context.Context, *request.Request) bool
// keyForConfig builds a key for identifying the configs during setup time // keyForConfig builds a key for identifying the configs during setup time
func keyForConfig(blocIndex int, blocKeyIndex int) string { func keyForConfig(blocIndex int, blocKeyIndex int) string {
return fmt.Sprintf("%d:%d", blocIndex, blocKeyIndex) return fmt.Sprintf("%d:%d", blocIndex, blocKeyIndex)

View File

@ -2,17 +2,31 @@ package dnsserver
import ( import (
"fmt" "fmt"
"regexp"
"sort" "sort"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
) )
// checkZoneSyntax() checks whether the given string match 1035 Preferred Syntax or not.
// The root zone, and all reverse zones always return true even though they technically don't meet 1035 Preferred Syntax
func checkZoneSyntax(zone string) bool {
if zone == "." || dnsutil.IsReverse(zone) != 0 {
return true
}
regex1035PreferredSyntax, _ := regexp.MatchString(`^(([A-Za-z]([A-Za-z0-9-]*[A-Za-z0-9])?)\.)+$`, zone)
return regex1035PreferredSyntax
}
// startUpZones creates the text that we show when starting up: // startUpZones creates the text that we show when starting up:
// grpc://example.com.:1055 // grpc://example.com.:1055
// example.com.:1053 on 127.0.0.1 // example.com.:1053 on 127.0.0.1
func startUpZones(protocol, addr string, zones map[string]*Config) string { func startUpZones(protocol, addr string, zones map[string][]*Config) string {
s := "" s := ""
keys := make([]string, len(zones)) keys := make([]string, len(zones))
i := 0 i := 0
for k := range zones { for k := range zones {
keys[i] = k keys[i] = k
i++ i++
@ -20,6 +34,9 @@ func startUpZones(protocol, addr string, zones map[string]*Config) string {
sort.Strings(keys) sort.Strings(keys)
for _, zone := range keys { for _, zone := range keys {
if !checkZoneSyntax(zone) {
s += fmt.Sprintf("Warning: Domain %q does not follow RFC1035 preferred syntax\n", zone)
}
// split addr into protocol, IP and Port // split addr into protocol, IP and Port
_, ip, port, err := SplitProtocolHostPort(addr) _, ip, port, err := SplitProtocolHostPort(addr)

View File

@ -138,14 +138,6 @@ func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddy
// MakeServers uses the newly-created siteConfigs to create and return a list of server instances. // MakeServers uses the newly-created siteConfigs to create and return a list of server instances.
func (h *dnsContext) MakeServers() ([]caddy.Server, error) { func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
// Now that all Keys and Directives are parsed and initialized
// lets verify that there is no overlap on the zones and addresses to listen for
errValid := h.validateZonesAndListeningAddresses()
if errValid != nil {
return nil, errValid
}
// Copy the Plugin, ListenHosts and Debug from first config in the block // Copy the Plugin, ListenHosts and Debug from first config in the block
// to all other config in the same block . Doing this results in zones // to all other config in the same block . Doing this results in zones
// sharing the same plugin instances and settings as other zones in // sharing the same plugin instances and settings as other zones in
@ -154,7 +146,9 @@ func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
c.Plugin = c.firstConfigInBlock.Plugin c.Plugin = c.firstConfigInBlock.Plugin
c.ListenHosts = c.firstConfigInBlock.ListenHosts c.ListenHosts = c.firstConfigInBlock.ListenHosts
c.Debug = c.firstConfigInBlock.Debug c.Debug = c.firstConfigInBlock.Debug
c.Stacktrace = c.firstConfigInBlock.Stacktrace
c.TLSConfig = c.firstConfigInBlock.TLSConfig c.TLSConfig = c.firstConfigInBlock.TLSConfig
c.TsigSecret = c.firstConfigInBlock.TsigSecret
} }
// we must map (group) each config to a bind address // we must map (group) each config to a bind address
@ -195,7 +189,27 @@ func (h *dnsContext) MakeServers() ([]caddy.Server, error) {
} }
servers = append(servers, s) servers = append(servers, s)
} }
}
// For each server config, check for View Filter plugins
for _, c := range h.configs {
// Add filters in the plugin.cfg order for consistent filter func evaluation order.
for _, d := range Directives {
if vf, ok := c.registry[d].(Viewer); ok {
if c.ViewName != "" {
return nil, fmt.Errorf("multiple views defined in server block")
}
c.ViewName = vf.ViewName()
c.FilterFuncs = append(c.FilterFuncs, vf.Filter)
}
}
}
// Verify that there is no overlap on the zones and listen addresses
// for unfiltered server configs
errValid := h.validateZonesAndListeningAddresses()
if errValid != nil {
return nil, errValid
} }
return servers, nil return servers, nil
@ -253,18 +267,24 @@ func (h *dnsContext) validateZonesAndListeningAddresses() error {
for _, h := range conf.ListenHosts { for _, h := range conf.ListenHosts {
// Validate the overlapping of ZoneAddr // Validate the overlapping of ZoneAddr
akey := zoneAddr{Transport: conf.Transport, Zone: conf.Zone, Address: h, Port: conf.Port} akey := zoneAddr{Transport: conf.Transport, Zone: conf.Zone, Address: h, Port: conf.Port}
existZone, overlapZone := checker.registerAndCheck(akey) var existZone, overlapZone *zoneAddr
if len(conf.FilterFuncs) > 0 {
// This config has filters. Check for overlap with other (unfiltered) configs.
existZone, overlapZone = checker.check(akey)
} else {
// This config has no filters. Check for overlap with other (unfiltered) configs,
// and register the zone to prevent subsequent zones from overlapping with it.
existZone, overlapZone = checker.registerAndCheck(akey)
}
if existZone != nil { if existZone != nil {
return fmt.Errorf("cannot serve %s - it is already defined", akey.String()) return fmt.Errorf("cannot serve %s - it is already defined", akey.String())
} }
if overlapZone != nil { if overlapZone != nil {
return fmt.Errorf("cannot serve %s - zone overlap listener capacity with %v", akey.String(), overlapZone.String()) return fmt.Errorf("cannot serve %s - zone overlap listener capacity with %v", akey.String(), overlapZone.String())
} }
} }
} }
return nil return nil
} }
// groupSiteConfigsByListenAddr groups site configs by their listen // groupSiteConfigsByListenAddr groups site configs by their listen

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"net" "net"
"runtime" "runtime"
"runtime/debug"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -36,22 +37,30 @@ type Server struct {
server [2]*dns.Server // 0 is a net.Listener, 1 is a net.PacketConn (a *UDPConn) in our case. server [2]*dns.Server // 0 is a net.Listener, 1 is a net.PacketConn (a *UDPConn) in our case.
m sync.Mutex // protects the servers m sync.Mutex // protects the servers
zones map[string]*Config // zones keyed by their address zones map[string][]*Config // zones keyed by their address
dnsWg sync.WaitGroup // used to wait on outstanding connections dnsWg sync.WaitGroup // used to wait on outstanding connections
graceTimeout time.Duration // the maximum duration of a graceful shutdown graceTimeout time.Duration // the maximum duration of a graceful shutdown
trace trace.Trace // the trace plugin for the server trace trace.Trace // the trace plugin for the server
debug bool // disable recover() debug bool // disable recover()
stacktrace bool // enable stacktrace in recover error log
classChaos bool // allow non-INET class queries classChaos bool // allow non-INET class queries
tsigSecret map[string]string
}
// MetadataCollector is a plugin that can retrieve metadata functions from all metadata providing plugins
type MetadataCollector interface {
Collect(context.Context, request.Request) context.Context
} }
// NewServer returns a new CoreDNS server and compiles all plugins in to it. By default CH class // NewServer returns a new CoreDNS server and compiles all plugins in to it. By default CH class
// queries are blocked unless queries from enableChaos are loaded. // queries are blocked unless queries from enableChaos are loaded.
func NewServer(addr string, group []*Config) (*Server, error) { func NewServer(addr string, group []*Config) (*Server, error) {
s := &Server{ s := &Server{
Addr: addr, Addr: addr,
zones: make(map[string]*Config), zones: make(map[string][]*Config),
graceTimeout: 5 * time.Second, graceTimeout: 5 * time.Second,
tsigSecret: make(map[string]string),
} }
// We have to bound our wg with one increment // We have to bound our wg with one increment
@ -67,8 +76,15 @@ func NewServer(addr string, group []*Config) (*Server, error) {
s.debug = true s.debug = true
log.D.Set() log.D.Set()
} }
// set the config per zone s.stacktrace = site.Stacktrace
s.zones[site.Zone] = site
// append the config to the zone's configs
s.zones[site.Zone] = append(s.zones[site.Zone], site)
// copy tsig secrets
for key, secret := range site.TsigSecret {
s.tsigSecret[key] = secret
}
// compile custom plugin for everything // compile custom plugin for everything
var stack plugin.Handler var stack plugin.Handler
@ -78,6 +94,12 @@ func NewServer(addr string, group []*Config) (*Server, error) {
// register the *handler* also // register the *handler* also
site.registerHandler(stack) site.registerHandler(stack)
// If the current plugin is a MetadataCollector, bookmark it for later use. This loop traverses the plugin
// list backwards, so the first MetadataCollector plugin wins.
if mdc, ok := stack.(MetadataCollector); ok {
site.metaCollector = mdc
}
if s.trace == nil && stack.Name() == "trace" { if s.trace == nil && stack.Name() == "trace" {
// we have to stash away the plugin, not the // we have to stash away the plugin, not the
// Tracer object, because the Tracer won't be initialized yet // Tracer object, because the Tracer won't be initialized yet
@ -112,7 +134,7 @@ func (s *Server) Serve(l net.Listener) error {
ctx := context.WithValue(context.Background(), Key{}, s) ctx := context.WithValue(context.Background(), Key{}, s)
ctx = context.WithValue(ctx, LoopKey{}, 0) ctx = context.WithValue(ctx, LoopKey{}, 0)
s.ServeDNS(ctx, w, r) s.ServeDNS(ctx, w, r)
})} }), TsigSecret: s.tsigSecret}
s.m.Unlock() s.m.Unlock()
return s.server[tcp].ActivateAndServe() return s.server[tcp].ActivateAndServe()
@ -126,7 +148,7 @@ func (s *Server) ServePacket(p net.PacketConn) error {
ctx := context.WithValue(context.Background(), Key{}, s) ctx := context.WithValue(context.Background(), Key{}, s)
ctx = context.WithValue(ctx, LoopKey{}, 0) ctx = context.WithValue(ctx, LoopKey{}, 0)
s.ServeDNS(ctx, w, r) s.ServeDNS(ctx, w, r)
})} }), TsigSecret: s.tsigSecret}
s.m.Unlock() s.m.Unlock()
return s.server[udp].ActivateAndServe() return s.server[udp].ActivateAndServe()
@ -163,7 +185,6 @@ func (s *Server) ListenPacket() (net.PacketConn, error) {
// immediately. // immediately.
// This implements Caddy.Stopper interface. // This implements Caddy.Stopper interface.
func (s *Server) Stop() (err error) { func (s *Server) Stop() (err error) {
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" {
// force connections to close after timeout // force connections to close after timeout
done := make(chan struct{}) done := make(chan struct{})
@ -213,7 +234,11 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
// In case the user doesn't enable error plugin, we still // In case the user doesn't enable error plugin, we still
// need to make sure that we stay alive up here // need to make sure that we stay alive up here
if rec := recover(); rec != nil { if rec := recover(); rec != nil {
if s.stacktrace {
log.Errorf("Recovered from panic in server: %q %v\n%s", s.Addr, rec, string(debug.Stack()))
} else {
log.Errorf("Recovered from panic in server: %q %v", s.Addr, rec) log.Errorf("Recovered from panic in server: %q %v", s.Addr, rec)
}
vars.Panic.Inc() vars.Panic.Inc()
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure) errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
} }
@ -241,11 +266,24 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
) )
for { for {
if h, ok := s.zones[q[off:]]; ok { if z, ok := s.zones[q[off:]]; ok {
for _, h := range z {
if h.pluginChain == nil { // zone defined, but has not got any plugins if h.pluginChain == nil { // zone defined, but has not got any plugins
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused) errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
return return
} }
if h.metaCollector != nil {
// Collect metadata now, so it can be used before we send a request down the plugin chain.
ctx = h.metaCollector.Collect(ctx, request.Request{Req: r, W: w})
}
// If all filter funcs pass, use this config.
if passAllFilterFuncs(ctx, h.FilterFuncs, &request.Request{Req: r, W: w}) {
if h.ViewName != "" {
// if there was a view defined for this Config, set the view name in the context
ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
}
if r.Question[0].Qtype != dns.TypeDS { if r.Question[0].Qtype != dns.TypeDS {
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r) rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
if !plugin.ClientWrite(rcode) { if !plugin.ClientWrite(rcode) {
@ -260,6 +298,8 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
// In all fairness: direct DS queries should not be needed. // In all fairness: direct DS queries should not be needed.
dshandler = h dshandler = h
} }
}
}
off, end = dns.NextLabel(q, off) off, end = dns.NextLabel(q, off)
if end { if end {
break break
@ -276,18 +316,46 @@ func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
} }
// Wildcard match, if we have found nothing try the root zone as a last resort. // Wildcard match, if we have found nothing try the root zone as a last resort.
if h, ok := s.zones["."]; ok && h.pluginChain != nil { if z, ok := s.zones["."]; ok {
for _, h := range z {
if h.pluginChain == nil {
continue
}
if h.metaCollector != nil {
// Collect metadata now, so it can be used before we send a request down the plugin chain.
ctx = h.metaCollector.Collect(ctx, request.Request{Req: r, W: w})
}
// If all filter funcs pass, use this config.
if passAllFilterFuncs(ctx, h.FilterFuncs, &request.Request{Req: r, W: w}) {
if h.ViewName != "" {
// if there was a view defined for this Config, set the view name in the context
ctx = context.WithValue(ctx, ViewKey{}, h.ViewName)
}
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r) rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
if !plugin.ClientWrite(rcode) { if !plugin.ClientWrite(rcode) {
errorFunc(s.Addr, w, r, rcode) errorFunc(s.Addr, w, r, rcode)
} }
return return
} }
}
}
// Still here? Error out with REFUSED. // Still here? Error out with REFUSED.
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused) errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
} }
// passAllFilterFuncs returns true if all filter funcs evaluate to true for the given request
func passAllFilterFuncs(ctx context.Context, filterFuncs []FilterFunc, req *request.Request) bool {
for _, ff := range filterFuncs {
if !ff(ctx, req) {
return false
}
}
return true
}
// OnStartupComplete lists the sites served by this server // OnStartupComplete lists the sites served by this server
// and any relevant information, assuming Quiet is false. // and any relevant information, assuming Quiet is false.
func (s *Server) OnStartupComplete() { func (s *Server) OnStartupComplete() {
@ -328,7 +396,7 @@ func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int
answer.SetRcode(r, rc) answer.SetRcode(r, rc)
state.SizeAndDo(answer) state.SizeAndDo(answer)
vars.Report(server, state, vars.Dropped, rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now()) vars.Report(server, state, vars.Dropped, "", rcode.ToString(rc), "" /* plugin */, answer.Len(), time.Now())
w.WriteMsg(answer) w.WriteMsg(answer)
} }
@ -344,6 +412,9 @@ type (
// LoopKey is the context key to detect server wide loops. // LoopKey is the context key to detect server wide loops.
LoopKey struct{} LoopKey struct{}
// ViewKey is the context key for the current view, if defined
ViewKey struct{}
) )
// EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default. // EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default.

View File

@ -22,6 +22,7 @@ import (
// ServergRPC represents an instance of a DNS-over-gRPC server. // ServergRPC represents an instance of a DNS-over-gRPC server.
type ServergRPC struct { type ServergRPC struct {
*Server *Server
*pb.UnimplementedDnsServiceServer
grpcServer *grpc.Server grpcServer *grpc.Server
listenAddr net.Addr listenAddr net.Addr
tlsConfig *tls.Config tlsConfig *tls.Config
@ -36,10 +37,12 @@ func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) {
// The *tls* plugin must make sure that multiple conflicting // The *tls* plugin must make sure that multiple conflicting
// TLS configuration returns an error: it can only be specified once. // TLS configuration returns an error: it can only be specified once.
var tlsConfig *tls.Config var tlsConfig *tls.Config
for _, conf := range s.zones { for _, z := range s.zones {
for _, conf := range z {
// Should we error if some configs *don't* have TLS? // Should we error if some configs *don't* have TLS?
tlsConfig = conf.TLSConfig tlsConfig = conf.TLSConfig
} }
}
// http/2 is required when using gRPC. We need to specify it in next protos // http/2 is required when using gRPC. We need to specify it in next protos
// or the upgrade won't happen. // or the upgrade won't happen.
if tlsConfig != nil { if tlsConfig != nil {
@ -81,7 +84,6 @@ func (s *ServergRPC) ServePacket(p net.PacketConn) error { return nil }
// Listen implements caddy.TCPServer interface. // Listen implements caddy.TCPServer interface.
func (s *ServergRPC) Listen() (net.Listener, error) { func (s *ServergRPC) Listen() (net.Listener, error) {
l, err := reuseport.Listen("tcp", s.Addr[len(transport.GRPC+"://"):]) l, err := reuseport.Listen("tcp", s.Addr[len(transport.GRPC+"://"):])
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -4,14 +4,17 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
stdlog "log"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
"time" "time"
"github.com/coredns/caddy" "github.com/coredns/caddy"
"github.com/coredns/coredns/plugin/metrics/vars"
"github.com/coredns/coredns/plugin/pkg/dnsutil" "github.com/coredns/coredns/plugin/pkg/dnsutil"
"github.com/coredns/coredns/plugin/pkg/doh" "github.com/coredns/coredns/plugin/pkg/doh"
clog "github.com/coredns/coredns/plugin/pkg/log"
"github.com/coredns/coredns/plugin/pkg/response" "github.com/coredns/coredns/plugin/pkg/response"
"github.com/coredns/coredns/plugin/pkg/reuseport" "github.com/coredns/coredns/plugin/pkg/reuseport"
"github.com/coredns/coredns/plugin/pkg/transport" "github.com/coredns/coredns/plugin/pkg/transport"
@ -26,6 +29,18 @@ type ServerHTTPS struct {
validRequest func(*http.Request) bool validRequest func(*http.Request) bool
} }
// loggerAdapter is a simple adapter around CoreDNS logger made to implement io.Writer in order to log errors from HTTP server
type loggerAdapter struct {
}
func (l *loggerAdapter) Write(p []byte) (n int, err error) {
clog.Debug(string(p))
return len(p), nil
}
// HTTPRequestKey is the context key for the current processed HTTP request (if current processed request was done over DOH)
type HTTPRequestKey struct{}
// NewServerHTTPS returns a new CoreDNS HTTPS server and compiles all plugins in to it. // NewServerHTTPS returns a new CoreDNS HTTPS server and compiles all plugins in to it.
func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) { func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
s, err := NewServer(addr, group) s, err := NewServer(addr, group)
@ -35,10 +50,12 @@ func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
// The *tls* plugin must make sure that multiple conflicting // The *tls* plugin must make sure that multiple conflicting
// TLS configuration returns an error: it can only be specified once. // TLS configuration returns an error: it can only be specified once.
var tlsConfig *tls.Config var tlsConfig *tls.Config
for _, conf := range s.zones { for _, z := range s.zones {
for _, conf := range z {
// Should we error if some configs *don't* have TLS? // Should we error if some configs *don't* have TLS?
tlsConfig = conf.TLSConfig tlsConfig = conf.TLSConfig
} }
}
// http/2 is recommended when using DoH. We need to specify it in next protos // http/2 is recommended when using DoH. We need to specify it in next protos
// or the upgrade won't happen. // or the upgrade won't happen.
@ -48,9 +65,11 @@ func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
// Use a custom request validation func or use the standard DoH path check. // Use a custom request validation func or use the standard DoH path check.
var validator func(*http.Request) bool var validator func(*http.Request) bool
for _, conf := range s.zones { for _, z := range s.zones {
for _, conf := range z {
validator = conf.HTTPRequestValidateFunc validator = conf.HTTPRequestValidateFunc
} }
}
if validator == nil { if validator == nil {
validator = func(r *http.Request) bool { return r.URL.Path == doh.Path } validator = func(r *http.Request) bool { return r.URL.Path == doh.Path }
} }
@ -59,6 +78,7 @@ func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
ReadTimeout: 5 * time.Second, ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second, IdleTimeout: 120 * time.Second,
ErrorLog: stdlog.New(&loggerAdapter{}, "", 0),
} }
sh := &ServerHTTPS{ sh := &ServerHTTPS{
Server: s, tlsConfig: tlsConfig, httpsServer: srv, validRequest: validator, Server: s, tlsConfig: tlsConfig, httpsServer: srv, validRequest: validator,
@ -88,7 +108,6 @@ func (s *ServerHTTPS) ServePacket(p net.PacketConn) error { return nil }
// Listen implements caddy.TCPServer interface. // Listen implements caddy.TCPServer interface.
func (s *ServerHTTPS) Listen() (net.Listener, error) { func (s *ServerHTTPS) Listen() (net.Listener, error) {
l, err := reuseport.Listen("tcp", s.Addr[len(transport.HTTPS+"://"):]) l, err := reuseport.Listen("tcp", s.Addr[len(transport.HTTPS+"://"):])
if err != nil { if err != nil {
return nil, err return nil, err
@ -125,15 +144,16 @@ func (s *ServerHTTPS) Stop() error {
// ServeHTTP is the handler that gets the HTTP request and converts to the dns format, calls the plugin // ServeHTTP is the handler that gets the HTTP request and converts to the dns format, calls the plugin
// chain, converts it back and write it to the client. // chain, converts it back and write it to the client.
func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !s.validRequest(r) { if !s.validRequest(r) {
http.Error(w, "", http.StatusNotFound) http.Error(w, "", http.StatusNotFound)
s.countResponse(http.StatusNotFound)
return return
} }
msg, err := doh.RequestToMsg(r) msg, err := doh.RequestToMsg(r)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
s.countResponse(http.StatusBadRequest)
return return
} }
@ -150,6 +170,7 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// We should expect a packet to be returned that we can send to the client. // We should expect a packet to be returned that we can send to the client.
ctx := context.WithValue(context.Background(), Key{}, s.Server) ctx := context.WithValue(context.Background(), Key{}, s.Server)
ctx = context.WithValue(ctx, LoopKey{}, 0) ctx = context.WithValue(ctx, LoopKey{}, 0)
ctx = context.WithValue(ctx, HTTPRequestKey{}, r)
s.ServeDNS(ctx, dw, msg) s.ServeDNS(ctx, dw, msg)
// See section 4.2.1 of RFC 8484. // See section 4.2.1 of RFC 8484.
@ -157,6 +178,7 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// handler has not provided any response message. // handler has not provided any response message.
if dw.Msg == nil { if dw.Msg == nil {
http.Error(w, "No response", http.StatusInternalServerError) http.Error(w, "No response", http.StatusInternalServerError)
s.countResponse(http.StatusInternalServerError)
return return
} }
@ -169,10 +191,15 @@ func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%f", age.Seconds())) w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%f", age.Seconds()))
w.Header().Set("Content-Length", strconv.Itoa(len(buf))) w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
s.countResponse(http.StatusOK)
w.Write(buf) w.Write(buf)
} }
func (s *ServerHTTPS) countResponse(status int) {
vars.HTTPSResponsesCount.WithLabelValues(s.Addr, strconv.Itoa(status)).Inc()
}
// Shutdown stops the server (non gracefully). // Shutdown stops the server (non gracefully).
func (s *ServerHTTPS) Shutdown() error { func (s *ServerHTTPS) Shutdown() error {
if s.httpsServer != nil { if s.httpsServer != nil {

View File

@ -28,10 +28,12 @@ func NewServerTLS(addr string, group []*Config) (*ServerTLS, error) {
// The *tls* plugin must make sure that multiple conflicting // The *tls* plugin must make sure that multiple conflicting
// TLS configuration returns an error: it can only be specified once. // TLS configuration returns an error: it can only be specified once.
var tlsConfig *tls.Config var tlsConfig *tls.Config
for _, conf := range s.zones { for _, z := range s.zones {
for _, conf := range z {
// Should we error if some configs *don't* have TLS? // Should we error if some configs *don't* have TLS?
tlsConfig = conf.TLSConfig tlsConfig = conf.TLSConfig
} }
}
return &ServerTLS{Server: s, tlsConfig: tlsConfig}, nil return &ServerTLS{Server: s, tlsConfig: tlsConfig}, nil
} }

View File

@ -0,0 +1,20 @@
package dnsserver
import (
"context"
"github.com/coredns/coredns/request"
)
// Viewer - If Viewer is implemented by a plugin in a server block, its Filter()
// is added to the server block's filter functions when starting the server. When a running server
// serves a DNS request, it will route the request to the first Config (server block) that passes
// all its filter functions.
type Viewer interface {
// Filter returns true if the server should use the server block in which the implementing plugin resides, and the
// name of the view for metrics logging.
Filter(ctx context.Context, req *request.Request) bool
// ViewName returns the name of the view
ViewName() string
}

View File

@ -34,6 +34,7 @@ var Directives = []string{
"any", "any",
"chaos", "chaos",
"loadbalance", "loadbalance",
"tsig",
"cache", "cache",
"rewrite", "rewrite",
"header", "header",
@ -59,4 +60,5 @@ var Directives = []string{
"whoami", "whoami",
"on", "on",
"sign", "sign",
"view",
} }

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path/filepath"
"runtime" "runtime"
"strings" "strings"
@ -95,7 +96,7 @@ func confLoader(serverType string) (caddy.Input, error) {
return caddy.CaddyfileFromPipe(os.Stdin, serverType) return caddy.CaddyfileFromPipe(os.Stdin, serverType)
} }
contents, err := os.ReadFile(conf) contents, err := os.ReadFile(filepath.Clean(conf))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -2,7 +2,7 @@ package coremain
// Various CoreDNS constants. // Various CoreDNS constants.
const ( const (
CoreVersion = "1.8.7" CoreVersion = "1.10.0"
coreName = "CoreDNS" coreName = "CoreDNS"
serverType = "dns" serverType = "dns"
) )

View File

@ -2,11 +2,18 @@
# from: https://github.com/golang/protobuf to make this work. # from: https://github.com/golang/protobuf to make this work.
# The generate dns.pb.go is checked into git, so for normal builds we don't need # The generate dns.pb.go is checked into git, so for normal builds we don't need
# to run this generation step. # to run this generation step.
# Note: The following has been used when regenerate pb:
# curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.19.4/protoc-3.19.4-linux-x86_64.zip
# go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.27.1
# go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2.0
# export PATH="$PATH:$(go env GOPATH)/bin"
# rm pb/dns.pb.go pb/dns_grpc.pb.go
# make pb
all: dns.pb.go all: dns.pb.go
dns.pb.go: dns.proto dns.pb.go: dns.proto
protoc --go_out=plugins=grpc:. dns.proto protoc --go_out=. --go-grpc_out=. dns.proto
.PHONY: clean .PHONY: clean
clean: clean:

View File

@ -1,156 +1,147 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.27.1
// protoc v3.19.4
// source: dns.proto // source: dns.proto
package pb package pb
import ( import (
context "context" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
fmt "fmt" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
math "math" reflect "reflect"
sync "sync"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
) )
// Reference imports to suppress errors if they are not otherwise used. const (
var _ = proto.Marshal // Verify that this generated code is sufficiently up-to-date.
var _ = fmt.Errorf _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
var _ = math.Inf // Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
/* Miek: disabled this manually, because I don't know what the heck */ )
/*
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
*/
type DnsPacket struct { type DnsPacket struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
} }
func (m *DnsPacket) Reset() { *m = DnsPacket{} } func (x *DnsPacket) Reset() {
func (m *DnsPacket) String() string { return proto.CompactTextString(m) } *x = DnsPacket{}
if protoimpl.UnsafeEnabled {
mi := &file_dns_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DnsPacket) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DnsPacket) ProtoMessage() {} func (*DnsPacket) ProtoMessage() {}
func (x *DnsPacket) ProtoReflect() protoreflect.Message {
mi := &file_dns_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DnsPacket.ProtoReflect.Descriptor instead.
func (*DnsPacket) Descriptor() ([]byte, []int) { func (*DnsPacket) Descriptor() ([]byte, []int) {
return fileDescriptor_638ff8d8aaf3d8ae, []int{0} return file_dns_proto_rawDescGZIP(), []int{0}
} }
func (m *DnsPacket) XXX_Unmarshal(b []byte) error { func (x *DnsPacket) GetMsg() []byte {
return xxx_messageInfo_DnsPacket.Unmarshal(m, b) if x != nil {
} return x.Msg
func (m *DnsPacket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DnsPacket.Marshal(b, m, deterministic)
}
func (m *DnsPacket) XXX_Merge(src proto.Message) {
xxx_messageInfo_DnsPacket.Merge(m, src)
}
func (m *DnsPacket) XXX_Size() int {
return xxx_messageInfo_DnsPacket.Size(m)
}
func (m *DnsPacket) XXX_DiscardUnknown() {
xxx_messageInfo_DnsPacket.DiscardUnknown(m)
}
var xxx_messageInfo_DnsPacket proto.InternalMessageInfo
func (m *DnsPacket) GetMsg() []byte {
if m != nil {
return m.Msg
} }
return nil return nil
} }
func init() { var File_dns_proto protoreflect.FileDescriptor
proto.RegisterType((*DnsPacket)(nil), "coredns.dns.DnsPacket")
var file_dns_proto_rawDesc = []byte{
0x0a, 0x09, 0x64, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x63, 0x6f, 0x72,
0x65, 0x64, 0x6e, 0x73, 0x2e, 0x64, 0x6e, 0x73, 0x22, 0x1d, 0x0a, 0x09, 0x44, 0x6e, 0x73, 0x50,
0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x45, 0x0a, 0x0a, 0x44, 0x6e, 0x73, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x16,
0x2e, 0x63, 0x6f, 0x72, 0x65, 0x64, 0x6e, 0x73, 0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6e, 0x73,
0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x64, 0x6e, 0x73,
0x2e, 0x64, 0x6e, 0x73, 0x2e, 0x44, 0x6e, 0x73, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x06,
0x5a, 0x04, 0x2e, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
func init() { proto.RegisterFile("dns.proto", fileDescriptor_638ff8d8aaf3d8ae) } var (
file_dns_proto_rawDescOnce sync.Once
file_dns_proto_rawDescData = file_dns_proto_rawDesc
)
var fileDescriptor_638ff8d8aaf3d8ae = []byte{ func file_dns_proto_rawDescGZIP() []byte {
// 120 bytes of a gzipped FileDescriptorProto file_dns_proto_rawDescOnce.Do(func() {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4c, 0xc9, 0x2b, 0xd6, file_dns_proto_rawDescData = protoimpl.X.CompressGZIP(file_dns_proto_rawDescData)
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x4e, 0xce, 0x2f, 0x4a, 0x05, 0x71, 0x53, 0xf2, 0x8a, })
0x95, 0x64, 0xb9, 0x38, 0x5d, 0xf2, 0x8a, 0x03, 0x12, 0x93, 0xb3, 0x53, 0x4b, 0x84, 0x04, 0xb8, return file_dns_proto_rawDescData
0x98, 0x73, 0x8b, 0xd3, 0x25, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x40, 0x4c, 0x23, 0x57, 0x2e,
0x2e, 0x97, 0xbc, 0xe2, 0xe0, 0xd4, 0xa2, 0xb2, 0xcc, 0xe4, 0x54, 0x21, 0x73, 0x2e, 0xd6, 0xc0,
0xd2, 0xd4, 0xa2, 0x4a, 0x21, 0x31, 0x3d, 0x24, 0x33, 0xf4, 0xe0, 0x06, 0x48, 0xe1, 0x10, 0x77,
0x62, 0x89, 0x62, 0x2a, 0x48, 0x4a, 0x62, 0x03, 0xdb, 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff,
0xf5, 0xd1, 0x3f, 0x26, 0x8c, 0x00, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. var file_dns_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var _ context.Context var file_dns_proto_goTypes = []interface{}{
var _ grpc.ClientConn (*DnsPacket)(nil), // 0: coredns.dns.DnsPacket
}
// This is a compile-time assertion to ensure that this generated file var file_dns_proto_depIdxs = []int32{
// is compatible with the grpc package it is being compiled against. 0, // 0: coredns.dns.DnsService.Query:input_type -> coredns.dns.DnsPacket
const _ = grpc.SupportPackageIsVersion4 0, // 1: coredns.dns.DnsService.Query:output_type -> coredns.dns.DnsPacket
1, // [1:2] is the sub-list for method output_type
// DnsServiceClient is the client API for DnsService service. 0, // [0:1] is the sub-list for method input_type
// 0, // [0:0] is the sub-list for extension type_name
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. 0, // [0:0] is the sub-list for extension extendee
type DnsServiceClient interface { 0, // [0:0] is the sub-list for field type_name
Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error)
} }
type dnsServiceClient struct { func init() { file_dns_proto_init() }
cc *grpc.ClientConn func file_dns_proto_init() {
if File_dns_proto != nil {
return
} }
if !protoimpl.UnsafeEnabled {
func NewDnsServiceClient(cc *grpc.ClientConn) DnsServiceClient { file_dns_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
return &dnsServiceClient{cc} switch v := v.(*DnsPacket); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
} }
func (c *dnsServiceClient) Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error) {
out := new(DnsPacket)
err := c.cc.Invoke(ctx, "/coredns.dns.DnsService/Query", in, out, opts...)
if err != nil {
return nil, err
} }
return out, nil
} }
type x struct{}
// DnsServiceServer is the server API for DnsService service. out := protoimpl.TypeBuilder{
type DnsServiceServer interface { File: protoimpl.DescBuilder{
Query(context.Context, *DnsPacket) (*DnsPacket, error) GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
} RawDescriptor: file_dns_proto_rawDesc,
NumEnums: 0,
func RegisterDnsServiceServer(s *grpc.Server, srv DnsServiceServer) { NumMessages: 1,
s.RegisterService(&_DnsService_serviceDesc, srv) NumExtensions: 0,
} NumServices: 1,
func _DnsService_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DnsPacket)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DnsServiceServer).Query(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/coredns.dns.DnsService/Query",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DnsServiceServer).Query(ctx, req.(*DnsPacket))
}
return interceptor(ctx, in, info, handler)
}
var _DnsService_serviceDesc = grpc.ServiceDesc{
ServiceName: "coredns.dns.DnsService",
HandlerType: (*DnsServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Query",
Handler: _DnsService_Query_Handler,
}, },
}, GoTypes: file_dns_proto_goTypes,
Streams: []grpc.StreamDesc{}, DependencyIndexes: file_dns_proto_depIdxs,
Metadata: "dns.proto", MessageInfos: file_dns_proto_msgTypes,
}.Build()
File_dns_proto = out.File
file_dns_proto_rawDesc = nil
file_dns_proto_goTypes = nil
file_dns_proto_depIdxs = nil
} }

View File

@ -1,7 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package coredns.dns; package coredns.dns;
option go_package = "pb"; option go_package = ".;pb";
message DnsPacket { message DnsPacket {
bytes msg = 1; bytes msg = 1;

105
vendor/github.com/coredns/coredns/pb/dns_grpc.pb.go generated vendored Normal file
View File

@ -0,0 +1,105 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.19.4
// source: dns.proto
package pb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// DnsServiceClient is the client API for DnsService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type DnsServiceClient interface {
Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error)
}
type dnsServiceClient struct {
cc grpc.ClientConnInterface
}
func NewDnsServiceClient(cc grpc.ClientConnInterface) DnsServiceClient {
return &dnsServiceClient{cc}
}
func (c *dnsServiceClient) Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error) {
out := new(DnsPacket)
err := c.cc.Invoke(ctx, "/coredns.dns.DnsService/Query", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DnsServiceServer is the server API for DnsService service.
// All implementations must embed UnimplementedDnsServiceServer
// for forward compatibility
type DnsServiceServer interface {
Query(context.Context, *DnsPacket) (*DnsPacket, error)
mustEmbedUnimplementedDnsServiceServer()
}
// UnimplementedDnsServiceServer must be embedded to have forward compatible implementations.
type UnimplementedDnsServiceServer struct {
}
func (UnimplementedDnsServiceServer) Query(context.Context, *DnsPacket) (*DnsPacket, error) {
return nil, status.Errorf(codes.Unimplemented, "method Query not implemented")
}
func (UnimplementedDnsServiceServer) mustEmbedUnimplementedDnsServiceServer() {}
// UnsafeDnsServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DnsServiceServer will
// result in compilation errors.
type UnsafeDnsServiceServer interface {
mustEmbedUnimplementedDnsServiceServer()
}
func RegisterDnsServiceServer(s grpc.ServiceRegistrar, srv DnsServiceServer) {
s.RegisterService(&DnsService_ServiceDesc, srv)
}
func _DnsService_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DnsPacket)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DnsServiceServer).Query(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/coredns.dns.DnsService/Query",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DnsServiceServer).Query(ctx, req.(*DnsPacket))
}
return interceptor(ctx, in, info, handler)
}
// DnsService_ServiceDesc is the grpc.ServiceDesc for DnsService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var DnsService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "coredns.dns.DnsService",
HandlerType: (*DnsServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Query",
Handler: _DnsService_Query_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "dns.proto",
}

View File

@ -14,22 +14,22 @@ import (
) )
// A returns A records from Backend or an error. // A returns A records from Backend or an error.
func A(ctx context.Context, b ServiceBackend, zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, err error) { func A(ctx context.Context, b ServiceBackend, zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, truncated bool, err error) {
services, err := checkForApex(ctx, b, zone, state, opt) services, err := checkForApex(ctx, b, zone, state, opt)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
dup := make(map[string]struct{}) dup := make(map[string]struct{})
for _, serv := range services { for _, serv := range services {
what, ip := serv.HostType() what, ip := serv.HostType()
switch what { switch what {
case dns.TypeCNAME: case dns.TypeCNAME:
if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) { if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
// x CNAME x is a direct loop, don't add those // x CNAME x is a direct loop, don't add those
// in etcd/skydns w.x CNAME x is also direct loop due to the "recursive" nature of search results
continue continue
} }
@ -44,7 +44,7 @@ func A(ctx context.Context, b ServiceBackend, zone string, state request.Request
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) { if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
state1 := state.NewWithQuestion(serv.Host, state.QType()) state1 := state.NewWithQuestion(serv.Host, state.QType())
state1.Zone = zone state1.Zone = zone
nextRecords, err := A(ctx, b, zone, state1, append(previousRecords, newRecord), opt) nextRecords, tc, err := A(ctx, b, zone, state1, append(previousRecords, newRecord), opt)
if err == nil { if err == nil {
// Not only have we found something we should add the CNAME and the IP addresses. // Not only have we found something we should add the CNAME and the IP addresses.
@ -53,6 +53,9 @@ func A(ctx context.Context, b ServiceBackend, zone string, state request.Request
records = append(records, nextRecords...) records = append(records, nextRecords...)
} }
} }
if tc {
truncated = true
}
continue continue
} }
// This means we can not complete the CNAME, try to look else where. // This means we can not complete the CNAME, try to look else where.
@ -62,6 +65,9 @@ func A(ctx context.Context, b ServiceBackend, zone string, state request.Request
if e1 != nil { if e1 != nil {
continue continue
} }
if m1.Truncated {
truncated = true
}
// Len(m1.Answer) > 0 here is well? // Len(m1.Answer) > 0 here is well?
records = append(records, newRecord) records = append(records, newRecord)
records = append(records, m1.Answer...) records = append(records, m1.Answer...)
@ -77,20 +83,19 @@ func A(ctx context.Context, b ServiceBackend, zone string, state request.Request
// nada // nada
} }
} }
return records, nil return records, truncated, nil
} }
// AAAA returns AAAA records from Backend or an error. // AAAA returns AAAA records from Backend or an error.
func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, err error) { func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, truncated bool, err error) {
services, err := checkForApex(ctx, b, zone, state, opt) services, err := checkForApex(ctx, b, zone, state, opt)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
dup := make(map[string]struct{}) dup := make(map[string]struct{})
for _, serv := range services { for _, serv := range services {
what, ip := serv.HostType() what, ip := serv.HostType()
switch what { switch what {
@ -98,6 +103,7 @@ func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Requ
// Try to resolve as CNAME if it's not an IP, but only if we don't create loops. // Try to resolve as CNAME if it's not an IP, but only if we don't create loops.
if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) { if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
// x CNAME x is a direct loop, don't add those // x CNAME x is a direct loop, don't add those
// in etcd/skydns w.x CNAME x is also direct loop due to the "recursive" nature of search results
continue continue
} }
@ -112,7 +118,7 @@ func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Requ
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) { if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
state1 := state.NewWithQuestion(serv.Host, state.QType()) state1 := state.NewWithQuestion(serv.Host, state.QType())
state1.Zone = zone state1.Zone = zone
nextRecords, err := AAAA(ctx, b, zone, state1, append(previousRecords, newRecord), opt) nextRecords, tc, err := AAAA(ctx, b, zone, state1, append(previousRecords, newRecord), opt)
if err == nil { if err == nil {
// Not only have we found something we should add the CNAME and the IP addresses. // Not only have we found something we should add the CNAME and the IP addresses.
@ -121,6 +127,9 @@ func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Requ
records = append(records, nextRecords...) records = append(records, nextRecords...)
} }
} }
if tc {
truncated = true
}
continue continue
} }
// This means we can not complete the CNAME, try to look else where. // This means we can not complete the CNAME, try to look else where.
@ -129,6 +138,9 @@ func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Requ
if e1 != nil { if e1 != nil {
continue continue
} }
if m1.Truncated {
truncated = true
}
// Len(m1.Answer) > 0 here is well? // Len(m1.Answer) > 0 here is well?
records = append(records, newRecord) records = append(records, newRecord)
records = append(records, m1.Answer...) records = append(records, m1.Answer...)
@ -145,7 +157,7 @@ func AAAA(ctx context.Context, b ServiceBackend, zone string, state request.Requ
} }
} }
} }
return records, nil return records, truncated, nil
} }
// SRV returns SRV records from the Backend. // SRV returns SRV records from the Backend.
@ -223,7 +235,7 @@ func SRV(ctx context.Context, b ServiceBackend, zone string, state request.Reque
// Internal name, we should have some info on them, either v4 or v6 // Internal name, we should have some info on them, either v4 or v6
// Clients expect a complete answer, because we are a recursor in their view. // Clients expect a complete answer, because we are a recursor in their view.
state1 := state.NewWithQuestion(srv.Target, dns.TypeA) state1 := state.NewWithQuestion(srv.Target, dns.TypeA)
addr, e1 := A(ctx, b, zone, state1, nil, opt) addr, _, e1 := A(ctx, b, zone, state1, nil, opt)
if e1 == nil { if e1 == nil {
extra = append(extra, addr...) extra = append(extra, addr...)
} }
@ -289,7 +301,7 @@ func MX(ctx context.Context, b ServiceBackend, zone string, state request.Reques
} }
// Internal name // Internal name
state1 := state.NewWithQuestion(mx.Mx, dns.TypeA) state1 := state.NewWithQuestion(mx.Mx, dns.TypeA)
addr, e1 := A(ctx, b, zone, state1, nil, opt) addr, _, e1 := A(ctx, b, zone, state1, nil, opt)
if e1 == nil { if e1 == nil {
extra = append(extra, addr...) extra = append(extra, addr...)
} }
@ -329,23 +341,22 @@ func CNAME(ctx context.Context, b ServiceBackend, zone string, state request.Req
} }
// TXT returns TXT records from Backend or an error. // TXT returns TXT records from Backend or an error.
func TXT(ctx context.Context, b ServiceBackend, zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, err error) { func TXT(ctx context.Context, b ServiceBackend, zone string, state request.Request, previousRecords []dns.RR, opt Options) (records []dns.RR, truncated bool, err error) {
services, err := b.Services(ctx, state, false, opt)
services, err := b.Services(ctx, state, true, opt)
if err != nil { if err != nil {
return nil, err return nil, false, err
} }
dup := make(map[string]struct{}) dup := make(map[string]struct{})
for _, serv := range services { for _, serv := range services {
what, _ := serv.HostType() what, _ := serv.HostType()
switch what { switch what {
case dns.TypeCNAME: case dns.TypeCNAME:
if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) { if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
// x CNAME x is a direct loop, don't add those // x CNAME x is a direct loop, don't add those
// in etcd/skydns w.x CNAME x is also direct loop due to the "recursive" nature of search results
continue continue
} }
@ -360,8 +371,10 @@ func TXT(ctx context.Context, b ServiceBackend, zone string, state request.Reque
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) { if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
state1 := state.NewWithQuestion(serv.Host, state.QType()) state1 := state.NewWithQuestion(serv.Host, state.QType())
state1.Zone = zone state1.Zone = zone
nextRecords, err := TXT(ctx, b, zone, state1, append(previousRecords, newRecord), opt) nextRecords, tc, err := TXT(ctx, b, zone, state1, append(previousRecords, newRecord), opt)
if tc {
truncated = true
}
if err == nil { if err == nil {
// Not only have we found something we should add the CNAME and the IP addresses. // Not only have we found something we should add the CNAME and the IP addresses.
if len(nextRecords) > 0 { if len(nextRecords) > 0 {
@ -384,15 +397,14 @@ func TXT(ctx context.Context, b ServiceBackend, zone string, state request.Reque
continue continue
case dns.TypeTXT: case dns.TypeTXT:
if _, ok := dup[serv.Host]; !ok { if _, ok := dup[serv.Text]; !ok {
dup[serv.Host] = struct{}{} dup[serv.Text] = struct{}{}
return append(records, serv.NewTXT(state.QName())), nil records = append(records, serv.NewTXT(state.QName()))
} }
} }
} }
return records, nil return records, truncated, nil
} }
// PTR returns the PTR records from the backend, only services that have a domain name as host are included. // PTR returns the PTR records from the backend, only services that have a domain name as host are included.
@ -490,7 +502,6 @@ func BackendError(ctx context.Context, b ServiceBackend, zone string, rcode int,
} }
func newAddress(s msg.Service, name string, ip net.IP, what uint16) dns.RR { func newAddress(s msg.Service, name string, ip net.IP, what uint16) dns.RR {
hdr := dns.RR_Header{Name: name, Rrtype: what, Class: dns.ClassINET, Ttl: s.TTL} hdr := dns.RR_Header{Name: name, Rrtype: what, Class: dns.ClassINET, Ttl: s.TTL}
if what == dns.TypeA { if what == dns.TypeA {

View File

@ -37,7 +37,9 @@ cache [TTL] [ZONES...] {
success CAPACITY [TTL] [MINTTL] success CAPACITY [TTL] [MINTTL]
denial CAPACITY [TTL] [MINTTL] denial CAPACITY [TTL] [MINTTL]
prefetch AMOUNT [[DURATION] [PERCENTAGE%]] prefetch AMOUNT [[DURATION] [PERCENTAGE%]]
serve_stale [DURATION] serve_stale [DURATION] [REFRESH_MODE]
servfail DURATION
disable success|denial [ZONES...]
} }
~~~ ~~~
@ -54,10 +56,20 @@ cache [TTL] [ZONES...] {
**DURATION** defaults to 1m. Prefetching will happen when the TTL drops below **PERCENTAGE**, **DURATION** defaults to 1m. Prefetching will happen when the TTL drops below **PERCENTAGE**,
which defaults to `10%`, or latest 1 second before TTL expiration. Values should be in the range `[10%, 90%]`. which defaults to `10%`, or latest 1 second before TTL expiration. Values should be in the range `[10%, 90%]`.
Note the percent sign is mandatory. **PERCENTAGE** is treated as an `int`. Note the percent sign is mandatory. **PERCENTAGE** is treated as an `int`.
* `serve_stale`, when serve\_stale is set, cache always will serve an expired entry to a client if there is one * `serve_stale`, when serve\_stale is set, cache will always serve an expired entry to a client if there is one
available. When this happens, cache will attempt to refresh the cache entry after sending the expired cache available as long as it has not been expired for longer than **DURATION** (default 1 hour). By default, the _cache_ plugin will
entry to the client. The responses have a TTL of 0. **DURATION** is how far back to consider attempt to refresh the cache entry after sending the expired cache entry to the client. The
stale responses as fresh. The default duration is 1h. responses have a TTL of 0. **REFRESH_MODE** controls the timing of the expired cache entry refresh.
`verify` will first verify that an entry is still unavailable from the source before sending the expired entry to the client.
`immediate` will immediately send the expired entry to the client before
checking to see if the entry is available from the source. **REFRESH_MODE** defaults to `immediate`. Setting this
value to `verify` can lead to increased latency when serving stale responses, but will prevent stale entries
from ever being served if an updated response can be retrieved from the source.
* `servfail` cache SERVFAIL responses for **DURATION**. Setting **DURATION** to 0 will disable caching of SERVFAIL
responses. If this option is not set, SERVFAIL responses will be cached for 5 seconds. **DURATION** may not be
greater than 5 minutes.
* `disable` disable the success or denial cache for the listed **ZONES**. If no **ZONES** are given, the specified
cache will be disabled for all zones.
## Capacity and Eviction ## Capacity and Eviction
@ -73,14 +85,14 @@ Entries with 0 TTL will remain in the cache until randomly evicted when the shar
If monitoring is enabled (via the *prometheus* plugin) then the following metrics are exported: If monitoring is enabled (via the *prometheus* plugin) then the following metrics are exported:
* `coredns_cache_entries{server, type}` - Total elements in the cache by cache type. * `coredns_cache_entries{server, type, zones, view}` - Total elements in the cache by cache type.
* `coredns_cache_hits_total{server, type}` - Counter of cache hits by cache type. * `coredns_cache_hits_total{server, type, zones, view}` - Counter of cache hits by cache type.
* `coredns_cache_misses_total{server}` - Counter of cache misses. - Deprecated, derive misses from cache hits/requests counters. * `coredns_cache_misses_total{server, zones, view}` - Counter of cache misses. - Deprecated, derive misses from cache hits/requests counters.
* `coredns_cache_requests_total{server}` - Counter of cache requests. * `coredns_cache_requests_total{server, zones, view}` - Counter of cache requests.
* `coredns_cache_prefetch_total{server}` - Counter of times the cache has prefetched a cached item. * `coredns_cache_prefetch_total{server, zones, view}` - Counter of times the cache has prefetched a cached item.
* `coredns_cache_drops_total{server}` - Counter of responses excluded from the cache due to request/response question name mismatch. * `coredns_cache_drops_total{server, zones, view}` - Counter of responses excluded from the cache due to request/response question name mismatch.
* `coredns_cache_served_stale_total{server}` - Counter of requests served from stale cache entries. * `coredns_cache_served_stale_total{server, zones, view}` - Counter of requests served from stale cache entries.
* `coredns_cache_evictions_total{server, type}` - Counter of cache evictions. * `coredns_cache_evictions_total{server, type, zones, view}` - Counter of cache evictions.
Cache types are either "denial" or "success". `Server` is the server handling the request, see the Cache types are either "denial" or "success". `Server` is the server handling the request, see the
prometheus plugin for documentation. prometheus plugin for documentation.
@ -115,3 +127,13 @@ example.org {
} }
} }
~~~ ~~~
Enable caching for `example.org`, but do not cache denials in `sub.example.org`:
~~~ corefile
example.org {
cache {
disable denial sub.example.org
}
}
~~~

View File

@ -21,6 +21,9 @@ type Cache struct {
Next plugin.Handler Next plugin.Handler
Zones []string Zones []string
zonesMetricLabel string
viewMetricLabel string
ncache *cache.Cache ncache *cache.Cache
ncap int ncap int
nttl time.Duration nttl time.Duration
@ -30,13 +33,20 @@ type Cache struct {
pcap int pcap int
pttl time.Duration pttl time.Duration
minpttl time.Duration minpttl time.Duration
failttl time.Duration // TTL for caching SERVFAIL responses
// Prefetch. // Prefetch.
prefetch int prefetch int
duration time.Duration duration time.Duration
percentage int percentage int
// Stale serve
staleUpTo time.Duration staleUpTo time.Duration
verifyStale bool
// Positive/negative zone exceptions
pexcept []string
nexcept []string
// Testing. // Testing.
now func() time.Time now func() time.Time
@ -55,6 +65,7 @@ func New() *Cache {
ncache: cache.New(defaultCap), ncache: cache.New(defaultCap),
nttl: maxNTTL, nttl: maxNTTL,
minnttl: minNTTL, minnttl: minNTTL,
failttl: minNTTL,
prefetch: 0, prefetch: 0,
duration: 1 * time.Minute, duration: 1 * time.Minute,
percentage: 10, percentage: 10,
@ -105,8 +116,14 @@ type ResponseWriter struct {
server string // Server handling the request. server string // Server handling the request.
do bool // When true the original request had the DO bit set. do bool // When true the original request had the DO bit set.
ad bool // When true the original request had the AD bit set.
prefetch bool // When true write nothing back to the client. prefetch bool // When true write nothing back to the client.
remoteAddr net.Addr remoteAddr net.Addr
wildcardFunc func() string // function to retrieve wildcard name that synthesized the result.
pexcept []string // positive zone exceptions
nexcept []string // negative zone exceptions
} }
// newPrefetchResponseWriter returns a Cache ResponseWriter to be used in // newPrefetchResponseWriter returns a Cache ResponseWriter to be used in
@ -153,8 +170,7 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
if mt == response.NameError || mt == response.NoData { if mt == response.NameError || mt == response.NoData {
duration = computeTTL(msgTTL, w.minnttl, w.nttl) duration = computeTTL(msgTTL, w.minnttl, w.nttl)
} else if mt == response.ServerError { } else if mt == response.ServerError {
// use default ttl which is 5s duration = w.failttl
duration = minTTL
} else { } else {
duration = computeTTL(msgTTL, w.minpttl, w.pttl) duration = computeTTL(msgTTL, w.minpttl, w.pttl)
} }
@ -162,11 +178,11 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
if hasKey && duration > 0 { if hasKey && duration > 0 {
if w.state.Match(res) { if w.state.Match(res) {
w.set(res, key, mt, duration) w.set(res, key, mt, duration)
cacheSize.WithLabelValues(w.server, Success).Set(float64(w.pcache.Len())) cacheSize.WithLabelValues(w.server, Success, w.zonesMetricLabel, w.viewMetricLabel).Set(float64(w.pcache.Len()))
cacheSize.WithLabelValues(w.server, Denial).Set(float64(w.ncache.Len())) cacheSize.WithLabelValues(w.server, Denial, w.zonesMetricLabel, w.viewMetricLabel).Set(float64(w.ncache.Len()))
} else { } else {
// Don't log it, but increment counter // Don't log it, but increment counter
cacheDrops.WithLabelValues(w.server).Inc() cacheDrops.WithLabelValues(w.server, w.zonesMetricLabel, w.viewMetricLabel).Inc()
} }
} }
@ -181,8 +197,10 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
res.Ns = filterRRSlice(res.Ns, ttl, w.do, false) res.Ns = filterRRSlice(res.Ns, ttl, w.do, false)
res.Extra = filterRRSlice(res.Extra, ttl, w.do, false) res.Extra = filterRRSlice(res.Extra, ttl, w.do, false)
if !w.do { if !w.do && !w.ad {
res.AuthenticatedData = false // unset AD bit if client is not OK with DNSSEC // unset AD bit if requester is not OK with DNSSEC
// But retain AD bit if requester set the AD bit in the request, per RFC6840 5.7-5.8
res.AuthenticatedData = false
} }
return w.ResponseWriter.WriteMsg(res) return w.ResponseWriter.WriteMsg(res)
@ -193,9 +211,16 @@ func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration
// and key is valid // and key is valid
switch mt { switch mt {
case response.NoError, response.Delegation: case response.NoError, response.Delegation:
if plugin.Zones(w.pexcept).Matches(m.Question[0].Name) != "" {
// zone is in exception list, do not cache
return
}
i := newItem(m, w.now(), duration) i := newItem(m, w.now(), duration)
if w.wildcardFunc != nil {
i.wildcard = w.wildcardFunc()
}
if w.pcache.Add(key, i) { if w.pcache.Add(key, i) {
evictions.WithLabelValues(w.server, Success).Inc() evictions.WithLabelValues(w.server, Success, w.zonesMetricLabel, w.viewMetricLabel).Inc()
} }
// when pre-fetching, remove the negative cache entry if it exists // when pre-fetching, remove the negative cache entry if it exists
if w.prefetch { if w.prefetch {
@ -203,9 +228,16 @@ func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration
} }
case response.NameError, response.NoData, response.ServerError: case response.NameError, response.NoData, response.ServerError:
if plugin.Zones(w.nexcept).Matches(m.Question[0].Name) != "" {
// zone is in exception list, do not cache
return
}
i := newItem(m, w.now(), duration) i := newItem(m, w.now(), duration)
if w.wildcardFunc != nil {
i.wildcard = w.wildcardFunc()
}
if w.ncache.Add(key, i) { if w.ncache.Add(key, i) {
evictions.WithLabelValues(w.server, Denial).Inc() evictions.WithLabelValues(w.server, Denial, w.zonesMetricLabel, w.viewMetricLabel).Inc()
} }
case response.OtherError: case response.OtherError:
@ -225,6 +257,33 @@ func (w *ResponseWriter) Write(buf []byte) (int, error) {
return n, err return n, err
} }
// verifyStaleResponseWriter is a response writer that only writes messages if they should replace a
// stale cache entry, and otherwise discards them.
type verifyStaleResponseWriter struct {
*ResponseWriter
refreshed bool // set to true if the last WriteMsg wrote to ResponseWriter, false otherwise.
}
// newVerifyStaleResponseWriter returns a ResponseWriter to be used when verifying stale cache
// entries. It only forward writes if an entry was successfully refreshed according to RFC8767,
// section 4 (response is NoError or NXDomain), and ignores any other response.
func newVerifyStaleResponseWriter(w *ResponseWriter) *verifyStaleResponseWriter {
return &verifyStaleResponseWriter{
w,
false,
}
}
// WriteMsg implements the dns.ResponseWriter interface.
func (w *verifyStaleResponseWriter) WriteMsg(res *dns.Msg) error {
w.refreshed = false
if res.Rcode == dns.RcodeSuccess || res.Rcode == dns.RcodeNameError {
w.refreshed = true
return w.ResponseWriter.WriteMsg(res) // stores to the cache and send to client
}
return nil // else discard
}
const ( const (
maxTTL = dnsutil.MaximumDefaulTTL maxTTL = dnsutil.MaximumDefaulTTL
minTTL = dnsutil.MinimalDefaultTTL minTTL = dnsutil.MinimalDefaultTTL

View File

@ -1,4 +1,4 @@
// +build gofuzz //go:build gofuzz
package cache package cache

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/coredns/coredns/plugin" "github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/metadata"
"github.com/coredns/coredns/plugin/metrics" "github.com/coredns/coredns/plugin/metrics"
"github.com/coredns/coredns/request" "github.com/coredns/coredns/request"
@ -17,6 +18,7 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
rc := r.Copy() // We potentially modify r, to prevent other plugins from seeing this (r is a pointer), copy r into rc. rc := r.Copy() // We potentially modify r, to prevent other plugins from seeing this (r is a pointer), copy r into rc.
state := request.Request{W: w, Req: rc} state := request.Request{W: w, Req: rc}
do := state.Do() do := state.Do()
ad := r.AuthenticatedData
zone := plugin.Zones(c.Zones).Matches(state.Name()) zone := plugin.Zones(c.Zones).Matches(state.Name())
if zone == "" { if zone == "" {
@ -35,31 +37,59 @@ func (c *Cache) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg)
ttl := 0 ttl := 0
i := c.getIgnoreTTL(now, state, server) i := c.getIgnoreTTL(now, state, server)
if i != nil {
ttl = i.ttl(now)
}
if i == nil { if i == nil {
crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do} crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do, ad: ad,
nexcept: c.nexcept, pexcept: c.pexcept, wildcardFunc: wildcardFunc(ctx)}
return c.doRefresh(ctx, state, crr) return c.doRefresh(ctx, state, crr)
} }
ttl = i.ttl(now)
if ttl < 0 { if ttl < 0 {
servedStale.WithLabelValues(server).Inc() // serve stale behavior
if c.verifyStale {
crr := &ResponseWriter{ResponseWriter: w, Cache: c, state: state, server: server, do: do}
cw := newVerifyStaleResponseWriter(crr)
ret, err := c.doRefresh(ctx, state, cw)
if cw.refreshed {
return ret, err
}
}
// Adjust the time to get a 0 TTL in the reply built from a stale item. // Adjust the time to get a 0 TTL in the reply built from a stale item.
now = now.Add(time.Duration(ttl) * time.Second) now = now.Add(time.Duration(ttl) * time.Second)
if !c.verifyStale {
cw := newPrefetchResponseWriter(server, state, c) cw := newPrefetchResponseWriter(server, state, c)
go c.doPrefetch(ctx, state, cw, i, now) go c.doPrefetch(ctx, state, cw, i, now)
}
servedStale.WithLabelValues(server, c.zonesMetricLabel, c.viewMetricLabel).Inc()
} else if c.shouldPrefetch(i, now) { } else if c.shouldPrefetch(i, now) {
cw := newPrefetchResponseWriter(server, state, c) cw := newPrefetchResponseWriter(server, state, c)
go c.doPrefetch(ctx, state, cw, i, now) go c.doPrefetch(ctx, state, cw, i, now)
} }
resp := i.toMsg(r, now, do)
w.WriteMsg(resp)
if i.wildcard != "" {
// Set wildcard source record name to metadata
metadata.SetValueFunc(ctx, "zone/wildcard", func() string {
return i.wildcard
})
}
resp := i.toMsg(r, now, do, ad)
w.WriteMsg(resp)
return dns.RcodeSuccess, nil return dns.RcodeSuccess, nil
} }
func wildcardFunc(ctx context.Context) func() string {
return func() string {
// Get wildcard source record name from metadata
if f := metadata.ValueFunc(ctx, "zone/wildcard"); f != nil {
return f()
}
return ""
}
}
func (c *Cache) doPrefetch(ctx context.Context, state request.Request, cw *ResponseWriter, i *item, now time.Time) { func (c *Cache) doPrefetch(ctx context.Context, state request.Request, cw *ResponseWriter, i *item, now time.Time) {
cachePrefetches.WithLabelValues(cw.server).Inc() cachePrefetches.WithLabelValues(cw.server, c.zonesMetricLabel, c.viewMetricLabel).Inc()
c.doRefresh(ctx, state, cw) c.doRefresh(ctx, state, cw)
// When prefetching we loose the item i, and with it the frequency // When prefetching we loose the item i, and with it the frequency
@ -70,7 +100,7 @@ func (c *Cache) doPrefetch(ctx context.Context, state request.Request, cw *Respo
} }
} }
func (c *Cache) doRefresh(ctx context.Context, state request.Request, cw *ResponseWriter) (int, error) { func (c *Cache) doRefresh(ctx context.Context, state request.Request, cw dns.ResponseWriter) (int, error) {
if !state.Do() { if !state.Do() {
setDo(state.Req) setDo(state.Req)
} }
@ -89,43 +119,28 @@ func (c *Cache) shouldPrefetch(i *item, now time.Time) bool {
// Name implements the Handler interface. // Name implements the Handler interface.
func (c *Cache) Name() string { return "cache" } func (c *Cache) Name() string { return "cache" }
func (c *Cache) get(now time.Time, state request.Request, server string) (*item, bool) {
k := hash(state.Name(), state.QType())
cacheRequests.WithLabelValues(server).Inc()
if i, ok := c.ncache.Get(k); ok && i.(*item).ttl(now) > 0 {
cacheHits.WithLabelValues(server, Denial).Inc()
return i.(*item), true
}
if i, ok := c.pcache.Get(k); ok && i.(*item).ttl(now) > 0 {
cacheHits.WithLabelValues(server, Success).Inc()
return i.(*item), true
}
cacheMisses.WithLabelValues(server).Inc()
return nil, false
}
// getIgnoreTTL unconditionally returns an item if it exists in the cache. // getIgnoreTTL unconditionally returns an item if it exists in the cache.
func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item { func (c *Cache) getIgnoreTTL(now time.Time, state request.Request, server string) *item {
k := hash(state.Name(), state.QType()) k := hash(state.Name(), state.QType())
cacheRequests.WithLabelValues(server).Inc() cacheRequests.WithLabelValues(server, c.zonesMetricLabel, c.viewMetricLabel).Inc()
if i, ok := c.ncache.Get(k); ok { if i, ok := c.ncache.Get(k); ok {
ttl := i.(*item).ttl(now) itm := i.(*item)
if ttl > 0 || (c.staleUpTo > 0 && -ttl < int(c.staleUpTo.Seconds())) { ttl := itm.ttl(now)
cacheHits.WithLabelValues(server, Denial).Inc() if itm.matches(state) && (ttl > 0 || (c.staleUpTo > 0 && -ttl < int(c.staleUpTo.Seconds()))) {
cacheHits.WithLabelValues(server, Denial, c.zonesMetricLabel, c.viewMetricLabel).Inc()
return i.(*item) return i.(*item)
} }
} }
if i, ok := c.pcache.Get(k); ok { if i, ok := c.pcache.Get(k); ok {
ttl := i.(*item).ttl(now) itm := i.(*item)
if ttl > 0 || (c.staleUpTo > 0 && -ttl < int(c.staleUpTo.Seconds())) { ttl := itm.ttl(now)
cacheHits.WithLabelValues(server, Success).Inc() if itm.matches(state) && (ttl > 0 || (c.staleUpTo > 0 && -ttl < int(c.staleUpTo.Seconds()))) {
cacheHits.WithLabelValues(server, Success, c.zonesMetricLabel, c.viewMetricLabel).Inc()
return i.(*item) return i.(*item)
} }
} }
cacheMisses.WithLabelValues(server).Inc() cacheMisses.WithLabelValues(server, c.zonesMetricLabel, c.viewMetricLabel).Inc()
return nil return nil
} }

View File

@ -1,20 +1,25 @@
package cache package cache
import ( import (
"strings"
"time" "time"
"github.com/coredns/coredns/plugin/cache/freq" "github.com/coredns/coredns/plugin/cache/freq"
"github.com/coredns/coredns/request"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
type item struct { type item struct {
Name string
QType uint16
Rcode int Rcode int
AuthenticatedData bool AuthenticatedData bool
RecursionAvailable bool RecursionAvailable bool
Answer []dns.RR Answer []dns.RR
Ns []dns.RR Ns []dns.RR
Extra []dns.RR Extra []dns.RR
wildcard string
origTTL uint32 origTTL uint32
stored time.Time stored time.Time
@ -24,6 +29,10 @@ type item struct {
func newItem(m *dns.Msg, now time.Time, d time.Duration) *item { func newItem(m *dns.Msg, now time.Time, d time.Duration) *item {
i := new(item) i := new(item)
if len(m.Question) != 0 {
i.Name = m.Question[0].Name
i.QType = m.Question[0].Qtype
}
i.Rcode = m.Rcode i.Rcode = m.Rcode
i.AuthenticatedData = m.AuthenticatedData i.AuthenticatedData = m.AuthenticatedData
i.RecursionAvailable = m.RecursionAvailable i.RecursionAvailable = m.RecursionAvailable
@ -56,7 +65,7 @@ func newItem(m *dns.Msg, now time.Time, d time.Duration) *item {
// So we're forced to always set this to 1; regardless if the answer came from the cache or not. // So we're forced to always set this to 1; regardless if the answer came from the cache or not.
// On newer systems(e.g. ubuntu 16.04 with glib version 2.23), this issue is resolved. // On newer systems(e.g. ubuntu 16.04 with glib version 2.23), this issue is resolved.
// So we may set this bit back to 0 in the future ? // So we may set this bit back to 0 in the future ?
func (i *item) toMsg(m *dns.Msg, now time.Time, do bool) *dns.Msg { func (i *item) toMsg(m *dns.Msg, now time.Time, do bool, ad bool) *dns.Msg {
m1 := new(dns.Msg) m1 := new(dns.Msg)
m1.SetReply(m) m1.SetReply(m)
@ -65,8 +74,10 @@ func (i *item) toMsg(m *dns.Msg, now time.Time, do bool) *dns.Msg {
// just set it to true. // just set it to true.
m1.Authoritative = true m1.Authoritative = true
m1.AuthenticatedData = i.AuthenticatedData m1.AuthenticatedData = i.AuthenticatedData
if !do { if !do && !ad {
m1.AuthenticatedData = false // when DNSSEC was not wanted, it can't be authenticated data. // When DNSSEC was not wanted, it can't be authenticated data.
// However, retain the AD bit if the requester set the AD bit, per RFC6840 5.7-5.8
m1.AuthenticatedData = false
} }
m1.RecursionAvailable = i.RecursionAvailable m1.RecursionAvailable = i.RecursionAvailable
m1.Rcode = i.Rcode m1.Rcode = i.Rcode
@ -87,3 +98,10 @@ func (i *item) ttl(now time.Time) int {
ttl := int(i.origTTL) - int(now.UTC().Sub(i.stored).Seconds()) ttl := int(i.origTTL) - int(now.UTC().Sub(i.stored).Seconds())
return ttl return ttl
} }
func (i *item) matches(state request.Request) bool {
if state.QType() == i.QType && strings.EqualFold(state.QName(), i.Name) {
return true
}
return false
}

View File

@ -14,54 +14,54 @@ var (
Subsystem: "cache", Subsystem: "cache",
Name: "entries", Name: "entries",
Help: "The number of elements in the cache.", Help: "The number of elements in the cache.",
}, []string{"server", "type"}) }, []string{"server", "type", "zones", "view"})
// cacheRequests is a counter of all requests through the cache. // cacheRequests is a counter of all requests through the cache.
cacheRequests = promauto.NewCounterVec(prometheus.CounterOpts{ cacheRequests = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "requests_total", Name: "requests_total",
Help: "The count of cache requests.", Help: "The count of cache requests.",
}, []string{"server"}) }, []string{"server", "zones", "view"})
// cacheHits is counter of cache hits by cache type. // cacheHits is counter of cache hits by cache type.
cacheHits = promauto.NewCounterVec(prometheus.CounterOpts{ cacheHits = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "hits_total", Name: "hits_total",
Help: "The count of cache hits.", Help: "The count of cache hits.",
}, []string{"server", "type"}) }, []string{"server", "type", "zones", "view"})
// cacheMisses is the counter of cache misses. - Deprecated // cacheMisses is the counter of cache misses. - Deprecated
cacheMisses = promauto.NewCounterVec(prometheus.CounterOpts{ cacheMisses = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "misses_total", Name: "misses_total",
Help: "The count of cache misses. Deprecated, derive misses from cache hits/requests counters.", Help: "The count of cache misses. Deprecated, derive misses from cache hits/requests counters.",
}, []string{"server"}) }, []string{"server", "zones", "view"})
// cachePrefetches is the number of time the cache has prefetched a cached item. // cachePrefetches is the number of time the cache has prefetched a cached item.
cachePrefetches = promauto.NewCounterVec(prometheus.CounterOpts{ cachePrefetches = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "prefetch_total", Name: "prefetch_total",
Help: "The number of times the cache has prefetched a cached item.", Help: "The number of times the cache has prefetched a cached item.",
}, []string{"server"}) }, []string{"server", "zones", "view"})
// cacheDrops is the number responses that are not cached, because the reply is malformed. // cacheDrops is the number responses that are not cached, because the reply is malformed.
cacheDrops = promauto.NewCounterVec(prometheus.CounterOpts{ cacheDrops = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "drops_total", Name: "drops_total",
Help: "The number responses that are not cached, because the reply is malformed.", Help: "The number responses that are not cached, because the reply is malformed.",
}, []string{"server"}) }, []string{"server", "zones", "view"})
// servedStale is the number of requests served from stale cache entries. // servedStale is the number of requests served from stale cache entries.
servedStale = promauto.NewCounterVec(prometheus.CounterOpts{ servedStale = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "served_stale_total", Name: "served_stale_total",
Help: "The number of requests served from stale cache entries.", Help: "The number of requests served from stale cache entries.",
}, []string{"server"}) }, []string{"server", "zones", "view"})
// evictions is the counter of cache evictions. // evictions is the counter of cache evictions.
evictions = promauto.NewCounterVec(prometheus.CounterOpts{ evictions = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: "cache", Subsystem: "cache",
Name: "evictions_total", Name: "evictions_total",
Help: "The count of cache evictions.", Help: "The count of cache evictions.",
}, []string{"server", "type"}) }, []string{"server", "type", "zones", "view"})
) )

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/coredns/caddy" "github.com/coredns/caddy"
@ -22,6 +23,12 @@ func setup(c *caddy.Controller) error {
if err != nil { if err != nil {
return plugin.Error("cache", err) return plugin.Error("cache", err)
} }
c.OnStartup(func() error {
ca.viewMetricLabel = dnsserver.GetConfig(c).ViewName
return nil
})
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler { dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
ca.Next = next ca.Next = next
return ca return ca
@ -165,11 +172,11 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
case "serve_stale": case "serve_stale":
args := c.RemainingArgs() args := c.RemainingArgs()
if len(args) > 1 { if len(args) > 2 {
return nil, c.ArgErr() return nil, c.ArgErr()
} }
ca.staleUpTo = 1 * time.Hour ca.staleUpTo = 1 * time.Hour
if len(args) == 1 { if len(args) > 0 {
d, err := time.ParseDuration(args[0]) d, err := time.ParseDuration(args[0])
if err != nil { if err != nil {
return nil, err return nil, err
@ -179,12 +186,67 @@ func cacheParse(c *caddy.Controller) (*Cache, error) {
} }
ca.staleUpTo = d ca.staleUpTo = d
} }
ca.verifyStale = false
if len(args) > 1 {
mode := strings.ToLower(args[1])
if mode != "immediate" && mode != "verify" {
return nil, fmt.Errorf("invalid value for serve_stale refresh mode: %s", mode)
}
ca.verifyStale = mode == "verify"
}
case "servfail":
args := c.RemainingArgs()
if len(args) != 1 {
return nil, c.ArgErr()
}
d, err := time.ParseDuration(args[0])
if err != nil {
return nil, err
}
if d < 0 {
return nil, errors.New("invalid negative ttl for servfail")
}
if d > 5*time.Minute {
// RFC 2308 prohibits caching SERVFAIL longer than 5 minutes
return nil, errors.New("caching SERVFAIL responses over 5 minutes is not permitted")
}
ca.failttl = d
case "disable":
// disable [success|denial] [zones]...
args := c.RemainingArgs()
if len(args) < 1 {
return nil, c.ArgErr()
}
var zones []string
if len(args) > 1 {
for _, z := range args[1:] { // args[1:] define the list of zones to disable
nz := plugin.Name(z).Normalize()
if nz == "" {
return nil, fmt.Errorf("invalid disabled zone: %s", z)
}
zones = append(zones, nz)
}
} else {
// if no zones specified, default to root
zones = []string{"."}
}
switch args[0] { // args[0] defines which cache to disable
case Denial:
ca.nexcept = zones
case Success:
ca.pexcept = zones
default:
return nil, fmt.Errorf("cache type for disable must be %q or %q", Success, Denial)
}
default: default:
return nil, c.ArgErr() return nil, c.ArgErr()
} }
} }
ca.Zones = origins ca.Zones = origins
ca.zonesMetricLabel = strings.Join(origins, ",")
ca.pcache = cache.New(ca.pcap) ca.pcache = cache.New(ca.pcap)
ca.ncache = cache.New(ca.ncap) ca.ncache = cache.New(ca.ncap)
} }

View File

@ -22,6 +22,9 @@ func Path(s, prefix string) string {
// Domain is the opposite of Path. // Domain is the opposite of Path.
func Domain(s string) string { func Domain(s string) string {
l := strings.Split(s, "/") l := strings.Split(s, "/")
if l[len(l)-1] == "" {
l = l[:len(l)-1]
}
// start with 1, to strip /skydns // start with 1, to strip /skydns
for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 { for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
l[i], l[j] = l[j], l[i] l[i], l[j] = l[j], l[i]

View File

@ -154,7 +154,6 @@ func split255(s string) []string {
} else { } else {
sx = append(sx, s[p:]) sx = append(sx, s[p:])
break break
} }
p, i = p+255, i+255 p, i = p+255, i+255
} }

View File

@ -15,11 +15,9 @@ import (
// //
// Note that a service can double/triple as a TXT record or MX record. // Note that a service can double/triple as a TXT record or MX record.
func (s *Service) HostType() (what uint16, normalized net.IP) { func (s *Service) HostType() (what uint16, normalized net.IP) {
ip := net.ParseIP(s.Host) ip := net.ParseIP(s.Host)
switch { switch {
case ip == nil: case ip == nil:
if len(s.Text) == 0 { if len(s.Text) == 0 {
return dns.TypeCNAME, nil return dns.TypeCNAME, nil

View File

@ -0,0 +1,49 @@
# metadata
## Name
*metadata* - enables a metadata collector.
## Description
By enabling *metadata* any plugin that implements [metadata.Provider
interface](https://godoc.org/github.com/coredns/coredns/plugin/metadata#Provider) will be called for
each DNS query, at the beginning of the process for that query, in order to add its own metadata to
context.
The metadata collected will be available for all plugins, via the Context parameter provided in the
ServeDNS function. The package (code) documentation has examples on how to inspect and retrieve
metadata a plugin might be interested in.
The metadata is added by setting a label with a value in the context. These labels should be named
`plugin/NAME`, where **NAME** is something descriptive. The only hard requirement the *metadata*
plugin enforces is that the labels contain a slash. See the documentation for
`metadata.SetValueFunc`.
The value stored is a string. The empty string signals "no metadata". See the documentation for
`metadata.ValueFunc` on how to retrieve this.
## Syntax
~~~
metadata [ZONES... ]
~~~
* **ZONES** zones metadata should be invoked for.
## Plugins
`metadata.Provider` interface needs to be implemented by each plugin willing to provide metadata
information for other plugins. It will be called by metadata and gather the information from all
plugins in context.
Note: this method should work quickly, because it is called for every request.
## Examples
The *rewrite* plugin uses meta data to rewrite requests.
## See Also
The [Provider interface](https://godoc.org/github.com/coredns/coredns/plugin/metadata#Provider) and
the [package level](https://godoc.org/github.com/coredns/coredns/plugin/metadata) documentation.

View File

@ -0,0 +1,44 @@
package metadata
import (
"context"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
// Metadata implements collecting metadata information from all plugins that
// implement the Provider interface.
type Metadata struct {
Zones []string
Providers []Provider
Next plugin.Handler
}
// Name implements the Handler interface.
func (m *Metadata) Name() string { return "metadata" }
// ContextWithMetadata is exported for use by provider tests
func ContextWithMetadata(ctx context.Context) context.Context {
return context.WithValue(ctx, key{}, md{})
}
// ServeDNS implements the plugin.Handler interface.
func (m *Metadata) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
rcode, err := plugin.NextOrFailure(m.Name(), m.Next, ctx, w, r)
return rcode, err
}
// Collect will retrieve metadata functions from each metadata provider and update the context
func (m *Metadata) Collect(ctx context.Context, state request.Request) context.Context {
ctx = ContextWithMetadata(ctx)
if plugin.Zones(m.Zones).Matches(state.Name()) != "" {
// Go through all Providers and collect metadata.
for _, p := range m.Providers {
ctx = p.Metadata(ctx, state)
}
}
return ctx
}

View File

@ -0,0 +1,127 @@
// Package metadata provides an API that allows plugins to add metadata to the context.
// Each metadata is stored under a label that has the form <plugin>/<name>. Each metadata
// is returned as a Func. When Func is called the metadata is returned. If Func is expensive to
// execute it is its responsibility to provide some form of caching. During the handling of a
// query it is expected the metadata stays constant.
//
// Basic example:
//
// Implement the Provider interface for a plugin p:
//
// func (p P) Metadata(ctx context.Context, state request.Request) context.Context {
// metadata.SetValueFunc(ctx, "test/something", func() string { return "myvalue" })
// return ctx
// }
//
// Basic example with caching:
//
// func (p P) Metadata(ctx context.Context, state request.Request) context.Context {
// cached := ""
// f := func() string {
// if cached != "" {
// return cached
// }
// cached = expensiveFunc()
// return cached
// }
// metadata.SetValueFunc(ctx, "test/something", f)
// return ctx
// }
//
// If you need access to this metadata from another plugin:
//
// // ...
// valueFunc := metadata.ValueFunc(ctx, "test/something")
// value := valueFunc()
// // use 'value'
//
package metadata
import (
"context"
"strings"
"github.com/coredns/coredns/request"
)
// Provider interface needs to be implemented by each plugin willing to provide
// metadata information for other plugins.
type Provider interface {
// Metadata adds metadata to the context and returns a (potentially) new context.
// Note: this method should work quickly, because it is called for every request
// from the metadata plugin.
Metadata(ctx context.Context, state request.Request) context.Context
}
// Func is the type of function in the metadata, when called they return the value of the label.
type Func func() string
// IsLabel checks that the provided name is a valid label name, i.e. two or more words separated by a slash.
func IsLabel(label string) bool {
p := strings.Index(label, "/")
if p <= 0 || p >= len(label)-1 {
// cannot accept namespace empty nor label empty
return false
}
return true
}
// Labels returns all metadata keys stored in the context. These label names should be named
// as: plugin/NAME, where NAME is something descriptive.
func Labels(ctx context.Context) []string {
if metadata := ctx.Value(key{}); metadata != nil {
if m, ok := metadata.(md); ok {
return keys(m)
}
}
return nil
}
// ValueFuncs returns the map[string]Func from the context, or nil if it does not exist.
func ValueFuncs(ctx context.Context) map[string]Func {
if metadata := ctx.Value(key{}); metadata != nil {
if m, ok := metadata.(md); ok {
return m
}
}
return nil
}
// ValueFunc returns the value function of label. If none can be found nil is returned. Calling the
// function returns the value of the label.
func ValueFunc(ctx context.Context, label string) Func {
if metadata := ctx.Value(key{}); metadata != nil {
if m, ok := metadata.(md); ok {
return m[label]
}
}
return nil
}
// SetValueFunc set the metadata label to the value function. If no metadata can be found this is a noop and
// false is returned. Any existing value is overwritten.
func SetValueFunc(ctx context.Context, label string, f Func) bool {
if metadata := ctx.Value(key{}); metadata != nil {
if m, ok := metadata.(md); ok {
m[label] = f
return true
}
}
return false
}
// md is metadata information storage.
type md map[string]Func
// key defines the type of key that is used to save metadata into the context.
type key struct{}
func keys(m map[string]Func) []string {
s := make([]string, len(m))
i := 0
for k := range m {
s[i] = k
i++
}
return s
}

View File

@ -0,0 +1,44 @@
package metadata
import (
"github.com/coredns/caddy"
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
)
func init() { plugin.Register("metadata", setup) }
func setup(c *caddy.Controller) error {
m, err := metadataParse(c)
if err != nil {
return err
}
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
m.Next = next
return m
})
c.OnStartup(func() error {
plugins := dnsserver.GetConfig(c).Handlers()
for _, p := range plugins {
if met, ok := p.(Provider); ok {
m.Providers = append(m.Providers, met)
}
}
return nil
})
return nil
}
func metadataParse(c *caddy.Controller) (*Metadata, error) {
m := &Metadata{}
c.Next()
m.Zones = plugin.OriginsFromArgsOrServerBlock(c.RemainingArgs(), c.ServerBlockKeys)
if c.NextBlock() || c.Next() {
return nil, plugin.Error("metadata", c.ArgErr())
}
return m, nil
}

View File

@ -8,19 +8,22 @@
With *prometheus* you export metrics from CoreDNS and any plugin that has them. With *prometheus* you export metrics from CoreDNS and any plugin that has them.
The default location for the metrics is `localhost:9153`. The metrics path is fixed to `/metrics`. The default location for the metrics is `localhost:9153`. The metrics path is fixed to `/metrics`.
The following metrics are exported:
In addition to the default Go metrics exported by the [Prometheus Go client](https://prometheus.io/docs/guides/go-application/),
the following metrics are exported:
* `coredns_build_info{version, revision, goversion}` - info about CoreDNS itself. * `coredns_build_info{version, revision, goversion}` - info about CoreDNS itself.
* `coredns_panics_total{}` - total number of panics. * `coredns_panics_total{}` - total number of panics.
* `coredns_dns_requests_total{server, zone, proto, family, type}` - total query count. * `coredns_dns_requests_total{server, zone, view, proto, family, type}` - total query count.
* `coredns_dns_request_duration_seconds{server, zone, type}` - duration to process each query. * `coredns_dns_request_duration_seconds{server, zone, view, type}` - duration to process each query.
* `coredns_dns_request_size_bytes{server, zone, proto}` - size of the request in bytes. * `coredns_dns_request_size_bytes{server, zone, view, proto}` - size of the request in bytes.
* `coredns_dns_do_requests_total{server, zone}` - queries that have the DO bit set * `coredns_dns_do_requests_total{server, view, zone}` - queries that have the DO bit set
* `coredns_dns_response_size_bytes{server, zone, proto}` - response size in bytes. * `coredns_dns_response_size_bytes{server, zone, view, proto}` - response size in bytes.
* `coredns_dns_responses_total{server, zone, rcode, plugin}` - response per zone, rcode and plugin. * `coredns_dns_responses_total{server, zone, view, rcode, plugin}` - response per zone, rcode and plugin.
* `coredns_plugin_enabled{server, zone, name}` - indicates whether a plugin is enabled on per server and zone basis. * `coredns_dns_https_responses_total{server, status}` - responses per server and http status code.
* `coredns_plugin_enabled{server, zone, view, name}` - indicates whether a plugin is enabled on per server, zone and view basis.
Each counter has a label `zone` which is the zonename used for the request/response. Almost each counter has a label `zone` which is the zonename used for the request/response.
Extra labels used are: Extra labels used are:
@ -32,12 +35,20 @@ Extra labels used are:
* `type` which holds the query type. It holds most common types (A, AAAA, MX, SOA, CNAME, PTR, TXT, * `type` which holds the query type. It holds most common types (A, AAAA, MX, SOA, CNAME, PTR, TXT,
NS, SRV, DS, DNSKEY, RRSIG, NSEC, NSEC3, HTTPS, IXFR, AXFR and ANY) and "other" which lumps together all NS, SRV, DS, DNSKEY, RRSIG, NSEC, NSEC3, HTTPS, IXFR, AXFR and ANY) and "other" which lumps together all
other types. other types.
* `status` which holds the https status code. Possible values are:
* 200 - request is processed,
* 404 - request has been rejected on validation,
* 400 - request to dns message conversion failed,
* 500 - processing ended up with no response.
* the `plugin` label holds the name of the plugin that made the write to the client. If the server * the `plugin` label holds the name of the plugin that made the write to the client. If the server
did the write (on error for instance), the value is empty. did the write (on error for instance), the value is empty.
If monitoring is enabled, queries that do not enter the plugin chain are exported under the fake If monitoring is enabled, queries that do not enter the plugin chain are exported under the fake
name "dropped" (without a closing dot - this is never a valid domain name). name "dropped" (without a closing dot - this is never a valid domain name).
Other plugins may export additional stats when the _prometheus_ plugin is enabled. Those stats are documented in each
plugin's README.
This plugin can only be used once per Server Block. This plugin can only be used once per Server Block.
## Syntax ## Syntax

View File

@ -22,3 +22,16 @@ func WithServer(ctx context.Context) string {
} }
return srv.(*dnsserver.Server).Addr return srv.(*dnsserver.Server).Addr
} }
// WithView returns the name of the view currently handling the request, if a view is defined.
//
// Basic usage with a metric:
//
// <metric>.WithLabelValues(metrics.WithView(ctx), labels..).Add(1)
func WithView(ctx context.Context) string {
v := ctx.Value(dnsserver.ViewKey{})
if v == nil {
return ""
}
return v.(string)
}

View File

@ -34,7 +34,7 @@ func (m *Metrics) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
rc = status rc = status
} }
plugin := m.authoritativePlugin(rw.Caller) plugin := m.authoritativePlugin(rw.Caller)
vars.Report(WithServer(ctx), state, zone, rcode.ToString(rc), plugin, rw.Len, rw.Start) vars.Report(WithServer(ctx), state, zone, WithView(ctx), rcode.ToString(rc), plugin, rw.Len, rw.Start)
return status, err return status, err
} }

View File

@ -24,7 +24,5 @@ func (r *Recorder) WriteMsg(res *dns.Msg) error {
_, r.Caller[0], _, _ = runtime.Caller(1) _, r.Caller[0], _, _ = runtime.Caller(1)
_, r.Caller[1], _, _ = runtime.Caller(2) _, r.Caller[1], _, _ = runtime.Caller(2)
_, r.Caller[2], _, _ = runtime.Caller(3) _, r.Caller[2], _, _ = runtime.Caller(3)
r.Len += res.Len() return r.Recorder.WriteMsg(res)
r.Msg = res
return r.ResponseWriter.WriteMsg(res)
} }

View File

@ -39,7 +39,7 @@ func setup(c *caddy.Controller) error {
for _, h := range conf.ListenHosts { for _, h := range conf.ListenHosts {
addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port) addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port)
for _, p := range conf.Handlers() { for _, p := range conf.Handlers() {
vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, p.Name()).Set(1) vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, conf.ViewName, p.Name()).Set(1)
} }
} }
return nil return nil
@ -49,7 +49,7 @@ func setup(c *caddy.Controller) error {
for _, h := range conf.ListenHosts { for _, h := range conf.ListenHosts {
addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port) addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port)
for _, p := range conf.Handlers() { for _, p := range conf.Handlers() {
vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, p.Name()).Set(1) vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, conf.ViewName, p.Name()).Set(1)
} }
} }
return nil return nil

View File

@ -9,7 +9,7 @@ import (
// Report reports the metrics data associated with request. This function is exported because it is also // Report reports the metrics data associated with request. This function is exported because it is also
// called from core/dnsserver to report requests hitting the server that should not be handled and are thus // called from core/dnsserver to report requests hitting the server that should not be handled and are thus
// not sent down the plugin chain. // not sent down the plugin chain.
func Report(server string, req request.Request, zone, rcode, plugin string, size int, start time.Time) { func Report(server string, req request.Request, zone, view, rcode, plugin string, size int, start time.Time) {
// Proto and Family. // Proto and Family.
net := req.Proto() net := req.Proto()
fam := "1" fam := "1"
@ -18,16 +18,16 @@ func Report(server string, req request.Request, zone, rcode, plugin string, size
} }
if req.Do() { if req.Do() {
RequestDo.WithLabelValues(server, zone).Inc() RequestDo.WithLabelValues(server, zone, view).Inc()
} }
qType := qTypeString(req.QType()) qType := qTypeString(req.QType())
RequestCount.WithLabelValues(server, zone, net, fam, qType).Inc() RequestCount.WithLabelValues(server, zone, view, net, fam, qType).Inc()
RequestDuration.WithLabelValues(server, zone).Observe(time.Since(start).Seconds()) RequestDuration.WithLabelValues(server, zone, view).Observe(time.Since(start).Seconds())
ResponseSize.WithLabelValues(server, zone, net).Observe(float64(size)) ResponseSize.WithLabelValues(server, zone, view, net).Observe(float64(size))
RequestSize.WithLabelValues(server, zone, net).Observe(float64(req.Len())) RequestSize.WithLabelValues(server, zone, view, net).Observe(float64(req.Len()))
ResponseRcode.WithLabelValues(server, zone, rcode, plugin).Inc() ResponseRcode.WithLabelValues(server, zone, view, rcode, plugin).Inc()
} }

View File

@ -14,7 +14,7 @@ var (
Subsystem: subsystem, Subsystem: subsystem,
Name: "requests_total", Name: "requests_total",
Help: "Counter of DNS requests made per zone, protocol and family.", Help: "Counter of DNS requests made per zone, protocol and family.",
}, []string{"server", "zone", "proto", "family", "type"}) }, []string{"server", "zone", "view", "proto", "family", "type"})
RequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ RequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
@ -22,7 +22,7 @@ var (
Name: "request_duration_seconds", Name: "request_duration_seconds",
Buckets: plugin.TimeBuckets, Buckets: plugin.TimeBuckets,
Help: "Histogram of the time (in seconds) each request took per zone.", Help: "Histogram of the time (in seconds) each request took per zone.",
}, []string{"server", "zone"}) }, []string{"server", "zone", "view"})
RequestSize = promauto.NewHistogramVec(prometheus.HistogramOpts{ RequestSize = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
@ -30,14 +30,14 @@ var (
Name: "request_size_bytes", Name: "request_size_bytes",
Help: "Size of the EDNS0 UDP buffer in bytes (64K for TCP) per zone and protocol.", Help: "Size of the EDNS0 UDP buffer in bytes (64K for TCP) per zone and protocol.",
Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3}, Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
}, []string{"server", "zone", "proto"}) }, []string{"server", "zone", "view", "proto"})
RequestDo = promauto.NewCounterVec(prometheus.CounterOpts{ RequestDo = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: subsystem, Subsystem: subsystem,
Name: "do_requests_total", Name: "do_requests_total",
Help: "Counter of DNS requests with DO bit set per zone.", Help: "Counter of DNS requests with DO bit set per zone.",
}, []string{"server", "zone"}) }, []string{"server", "zone", "view"})
ResponseSize = promauto.NewHistogramVec(prometheus.HistogramOpts{ ResponseSize = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
@ -45,14 +45,14 @@ var (
Name: "response_size_bytes", Name: "response_size_bytes",
Help: "Size of the returned response in bytes.", Help: "Size of the returned response in bytes.",
Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3}, Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
}, []string{"server", "zone", "proto"}) }, []string{"server", "zone", "view", "proto"})
ResponseRcode = promauto.NewCounterVec(prometheus.CounterOpts{ ResponseRcode = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Subsystem: subsystem, Subsystem: subsystem,
Name: "responses_total", Name: "responses_total",
Help: "Counter of response status codes.", Help: "Counter of response status codes.",
}, []string{"server", "zone", "rcode", "plugin"}) }, []string{"server", "zone", "view", "rcode", "plugin"})
Panic = promauto.NewCounter(prometheus.CounterOpts{ Panic = promauto.NewCounter(prometheus.CounterOpts{
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
@ -64,7 +64,14 @@ var (
Namespace: plugin.Namespace, Namespace: plugin.Namespace,
Name: "plugin_enabled", Name: "plugin_enabled",
Help: "A metric that indicates whether a plugin is enabled on per server and zone basis.", Help: "A metric that indicates whether a plugin is enabled on per server and zone basis.",
}, []string{"server", "zone", "name"}) }, []string{"server", "zone", "view", "name"})
HTTPSResponsesCount = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: plugin.Namespace,
Subsystem: subsystem,
Name: "https_responses_total",
Help: "Counter of DoH responses per server and http status code.",
}, []string{"server", "status"})
) )
const ( const (

View File

@ -125,7 +125,6 @@ func (h Host) NormalizeExact() []string {
} }
for i := range hosts { for i := range hosts {
hosts[i] = Name(hosts[i]).Normalize() hosts[i] = Name(hosts[i]).Normalize()
} }
return hosts return hosts
} }

View File

@ -66,7 +66,7 @@ func (c *Cache) Remove(key uint64) {
// Len returns the number of elements in the cache. // Len returns the number of elements in the cache.
func (c *Cache) Len() int { func (c *Cache) Len() int {
l := 0 l := 0
for _, s := range c.shards { for _, s := range &c.shards {
l += s.Len() l += s.Len()
} }
return l return l
@ -74,7 +74,7 @@ func (c *Cache) Len() int {
// Walk walks each shard in the cache. // Walk walks each shard in the cache.
func (c *Cache) Walk(f func(map[uint64]interface{}, uint64) bool) { func (c *Cache) Walk(f func(map[uint64]interface{}, uint64) bool) {
for _, s := range c.shards { for _, s := range &c.shards {
s.Walk(f) s.Walk(f)
} }
} }

View File

@ -38,7 +38,7 @@ func Split(n *net.IPNet) []string {
func nets(network *net.IPNet, newPrefixLen int) []*net.IPNet { func nets(network *net.IPNet, newPrefixLen int) []*net.IPNet {
prefixLen, _ := network.Mask.Size() prefixLen, _ := network.Mask.Size()
maxSubnets := int(math.Exp2(float64(newPrefixLen)) / math.Exp2(float64(prefixLen))) maxSubnets := int(math.Exp2(float64(newPrefixLen)) / math.Exp2(float64(prefixLen)))
nets := []*net.IPNet{{network.IP, net.CIDRMask(newPrefixLen, 8*len(network.IP))}} nets := []*net.IPNet{{IP: network.IP, Mask: net.CIDRMask(newPrefixLen, 8*len(network.IP))}}
for i := 1; i < maxSubnets; i++ { for i := 1; i < maxSubnets; i++ {
next, exceeds := cidr.NextSubnet(nets[len(nets)-1], newPrefixLen) next, exceeds := cidr.NextSubnet(nets[len(nets)-1], newPrefixLen)

View File

@ -92,7 +92,7 @@ func requestToMsgGet(req *http.Request) (*dns.Msg, error) {
} }
func toMsg(r io.ReadCloser) (*dns.Msg, error) { func toMsg(r io.ReadCloser) (*dns.Msg, error) {
buf, err := io.ReadAll(r) buf, err := io.ReadAll(http.MaxBytesReader(nil, r, 65536))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -0,0 +1,141 @@
package log
import (
"sync"
)
// Listener listens for all log prints of plugin loggers aka loggers with plugin name.
// When a plugin logger gets called, it should first call the same method in the Listener object.
// A usage example is, the external plugin k8s_event will replicate log prints to Kubernetes events.
type Listener interface {
Name() string
Debug(plugin string, v ...interface{})
Debugf(plugin string, format string, v ...interface{})
Info(plugin string, v ...interface{})
Infof(plugin string, format string, v ...interface{})
Warning(plugin string, v ...interface{})
Warningf(plugin string, format string, v ...interface{})
Error(plugin string, v ...interface{})
Errorf(plugin string, format string, v ...interface{})
Fatal(plugin string, v ...interface{})
Fatalf(plugin string, format string, v ...interface{})
}
type listeners struct {
listeners []Listener
sync.RWMutex
}
var ls *listeners
func init() {
ls = &listeners{}
ls.listeners = make([]Listener, 0)
}
// RegisterListener register a listener object.
func RegisterListener(new Listener) error {
ls.Lock()
defer ls.Unlock()
for k, l := range ls.listeners {
if l.Name() == new.Name() {
ls.listeners[k] = new
return nil
}
}
ls.listeners = append(ls.listeners, new)
return nil
}
// DeregisterListener deregister a listener object.
func DeregisterListener(old Listener) error {
ls.Lock()
defer ls.Unlock()
for k, l := range ls.listeners {
if l.Name() == old.Name() {
ls.listeners = append(ls.listeners[:k], ls.listeners[k+1:]...)
return nil
}
}
return nil
}
func (ls *listeners) debug(plugin string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Debug(plugin, v...)
}
ls.RUnlock()
}
func (ls *listeners) debugf(plugin string, format string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Debugf(plugin, format, v...)
}
ls.RUnlock()
}
func (ls *listeners) info(plugin string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Info(plugin, v...)
}
ls.RUnlock()
}
func (ls *listeners) infof(plugin string, format string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Infof(plugin, format, v...)
}
ls.RUnlock()
}
func (ls *listeners) warning(plugin string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Warning(plugin, v...)
}
ls.RUnlock()
}
func (ls *listeners) warningf(plugin string, format string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Warningf(plugin, format, v...)
}
ls.RUnlock()
}
func (ls *listeners) error(plugin string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Error(plugin, v...)
}
ls.RUnlock()
}
func (ls *listeners) errorf(plugin string, format string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Errorf(plugin, format, v...)
}
ls.RUnlock()
}
func (ls *listeners) fatal(plugin string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Fatal(plugin, v...)
}
ls.RUnlock()
}
func (ls *listeners) fatalf(plugin string, format string, v ...interface{}) {
ls.RLock()
for _, l := range ls.listeners {
l.Fatalf(plugin, format, v...)
}
ls.RUnlock()
}

View File

@ -27,6 +27,7 @@ func (p P) Debug(v ...interface{}) {
if !D.Value() { if !D.Value() {
return return
} }
ls.debug(p.plugin, v...)
p.log(debug, v...) p.log(debug, v...)
} }
@ -35,29 +36,56 @@ func (p P) Debugf(format string, v ...interface{}) {
if !D.Value() { if !D.Value() {
return return
} }
ls.debugf(p.plugin, format, v...)
p.logf(debug, format, v...) p.logf(debug, format, v...)
} }
// Info logs as log.Info. // Info logs as log.Info.
func (p P) Info(v ...interface{}) { p.log(info, v...) } func (p P) Info(v ...interface{}) {
ls.info(p.plugin, v...)
p.log(info, v...)
}
// Infof logs as log.Infof. // Infof logs as log.Infof.
func (p P) Infof(format string, v ...interface{}) { p.logf(info, format, v...) } func (p P) Infof(format string, v ...interface{}) {
ls.infof(p.plugin, format, v...)
p.logf(info, format, v...)
}
// Warning logs as log.Warning. // Warning logs as log.Warning.
func (p P) Warning(v ...interface{}) { p.log(warning, v...) } func (p P) Warning(v ...interface{}) {
ls.warning(p.plugin, v...)
p.log(warning, v...)
}
// Warningf logs as log.Warningf. // Warningf logs as log.Warningf.
func (p P) Warningf(format string, v ...interface{}) { p.logf(warning, format, v...) } func (p P) Warningf(format string, v ...interface{}) {
ls.warningf(p.plugin, format, v...)
p.logf(warning, format, v...)
}
// Error logs as log.Error. // Error logs as log.Error.
func (p P) Error(v ...interface{}) { p.log(err, v...) } func (p P) Error(v ...interface{}) {
ls.error(p.plugin, v...)
p.log(err, v...)
}
// Errorf logs as log.Errorf. // Errorf logs as log.Errorf.
func (p P) Errorf(format string, v ...interface{}) { p.logf(err, format, v...) } func (p P) Errorf(format string, v ...interface{}) {
ls.errorf(p.plugin, format, v...)
p.logf(err, format, v...)
}
// Fatal logs as log.Fatal and calls os.Exit(1). // Fatal logs as log.Fatal and calls os.Exit(1).
func (p P) Fatal(v ...interface{}) { p.log(fatal, v...); os.Exit(1) } func (p P) Fatal(v ...interface{}) {
ls.fatal(p.plugin, v...)
p.log(fatal, v...)
os.Exit(1)
}
// Fatalf logs as log.Fatalf and calls os.Exit(1). // Fatalf logs as log.Fatalf and calls os.Exit(1).
func (p P) Fatalf(format string, v ...interface{}) { p.logf(fatal, format, v...); os.Exit(1) } func (p P) Fatalf(format string, v ...interface{}) {
ls.fatalf(p.plugin, format, v...)
p.logf(fatal, format, v...)
os.Exit(1)
}

View File

@ -32,7 +32,6 @@ func stripZone(host string) string {
func HostPortOrFile(s ...string) ([]string, error) { func HostPortOrFile(s ...string) ([]string, error) {
var servers []string var servers []string
for _, h := range s { for _, h := range s {
trans, host := Transport(h) trans, host := Transport(h)
addr, _, err := net.SplitHostPort(host) addr, _, err := net.SplitHostPort(host)

View File

@ -1,4 +1,4 @@
// +build !go1.11 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd //go:build !go1.11 || (!aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd)
package reuseport package reuseport

View File

@ -1,5 +1,4 @@
// +build go1.11 //go:build go1.11 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd)
// +build aix darwin dragonfly freebsd linux netbsd openbsd
package reuseport package reuseport

View File

@ -82,6 +82,9 @@ func PTR(rr string) *dns.PTR { r, _ := dns.NewRR(rr); return r.(*dns.PTR) }
// TXT returns a TXT record from rr. It panics on errors. // TXT returns a TXT record from rr. It panics on errors.
func TXT(rr string) *dns.TXT { r, _ := dns.NewRR(rr); return r.(*dns.TXT) } func TXT(rr string) *dns.TXT { r, _ := dns.NewRR(rr); return r.(*dns.TXT) }
// CAA returns a CAA record from rr. It panics on errors.
func CAA(rr string) *dns.CAA { r, _ := dns.NewRR(rr); return r.(*dns.CAA) }
// HINFO returns a HINFO record from rr. It panics on errors. // HINFO returns a HINFO record from rr. It panics on errors.
func HINFO(rr string) *dns.HINFO { r, _ := dns.NewRR(rr); return r.(*dns.HINFO) } func HINFO(rr string) *dns.HINFO { r, _ := dns.NewRR(rr); return r.(*dns.HINFO) }
@ -282,7 +285,6 @@ func SortAndCheck(resp *dns.Msg, tc Case) error {
} }
if err := Section(tc, Ns, resp.Ns); err != nil { if err := Section(tc, Ns, resp.Ns); err != nil {
return err return err
} }
return Section(tc, Extra, resp.Extra) return Section(tc, Extra, resp.Extra)
} }

View File

@ -12,6 +12,7 @@ import (
type ResponseWriter struct { type ResponseWriter struct {
TCP bool // if TCP is true we return an TCP connection instead of an UDP one. TCP bool // if TCP is true we return an TCP connection instead of an UDP one.
RemoteIP string RemoteIP string
Zone string
} }
// LocalAddr returns the local address, 127.0.0.1:53 (UDP, TCP if t.TCP is true). // LocalAddr returns the local address, 127.0.0.1:53 (UDP, TCP if t.TCP is true).
@ -33,9 +34,9 @@ func (t *ResponseWriter) RemoteAddr() net.Addr {
ip := net.ParseIP(remoteIP) ip := net.ParseIP(remoteIP)
port := 40212 port := 40212
if t.TCP { if t.TCP {
return &net.TCPAddr{IP: ip, Port: port, Zone: ""} return &net.TCPAddr{IP: ip, Port: port, Zone: t.Zone}
} }
return &net.UDPAddr{IP: ip, Port: port, Zone: ""} return &net.UDPAddr{IP: ip, Port: port, Zone: t.Zone}
} }
// WriteMsg implements dns.ResponseWriter interface. // WriteMsg implements dns.ResponseWriter interface.

View File

@ -80,7 +80,6 @@ func Scrape(url string) []*MetricFamily {
// ScrapeMetricAsInt provides a sum of all metrics collected for the name and label provided. // ScrapeMetricAsInt provides a sum of all metrics collected for the name and label provided.
// if the metric is not a numeric value, it will be counted a 0. // if the metric is not a numeric value, it will be counted a 0.
func ScrapeMetricAsInt(addr string, name string, label string, nometricvalue int) int { func ScrapeMetricAsInt(addr string, name string, label string, nometricvalue int) int {
valueToInt := func(m metric) int { valueToInt := func(m metric) int {
v := m.Value v := m.Value
r, err := strconv.Atoi(v) r, err := strconv.Atoi(v)
@ -141,7 +140,6 @@ func MetricValueLabel(name, label string, mfs []*MetricFamily) (string, map[stri
return m.(metric).Value, m.(metric).Labels return m.(metric).Value, m.(metric).Labels
} }
} }
} }
} }
} }

View File

@ -313,7 +313,6 @@ func (r *Request) Class() string {
} }
return dns.Class(r.Req.Question[0].Qclass).String() return dns.Class(r.Req.Question[0].Qclass).String()
} }
// QClass returns the class of the question in the request. // QClass returns the class of the question in the request.
@ -327,7 +326,6 @@ func (r *Request) QClass() uint16 {
} }
return r.Req.Question[0].Qclass return r.Req.Question[0].Qclass
} }
// Clear clears all caching from Request s. // Clear clears all caching from Request s.

View File

@ -76,6 +76,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://www.misaka.io/services/dns * https://www.misaka.io/services/dns
* https://ping.sx/dig * https://ping.sx/dig
* https://fleetdeck.io/ * https://fleetdeck.io/
* https://github.com/markdingo/autoreverse
Send pull request if you want to be listed here. Send pull request if you want to be listed here.

View File

@ -18,6 +18,18 @@ const (
tcpIdleTimeout time.Duration = 8 * time.Second tcpIdleTimeout time.Duration = 8 * time.Second
) )
func isPacketConn(c net.Conn) bool {
if _, ok := c.(net.PacketConn); !ok {
return false
}
if ua, ok := c.LocalAddr().(*net.UnixAddr); ok {
return ua.Net == "unixgram" || ua.Net == "unixpacket"
}
return true
}
// A Conn represents a connection to a DNS server. // A Conn represents a connection to a DNS server.
type Conn struct { type Conn struct {
net.Conn // a net.Conn holding the connection net.Conn // a net.Conn holding the connection
@ -27,6 +39,14 @@ type Conn struct {
tsigRequestMAC string tsigRequestMAC string
} }
func (co *Conn) tsigProvider() TsigProvider {
if co.TsigProvider != nil {
return co.TsigProvider
}
// tsigSecretProvider will return ErrSecret if co.TsigSecret is nil.
return tsigSecretProvider(co.TsigSecret)
}
// A Client defines parameters for a DNS client. // A Client defines parameters for a DNS client.
type Client struct { type Client struct {
Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP) Net string // if "tcp" or "tcp-tls" (DNS over TLS) a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
@ -221,7 +241,7 @@ func (c *Client) exchangeContext(ctx context.Context, m *Msg, co *Conn) (r *Msg,
return nil, 0, err return nil, 0, err
} }
if _, ok := co.Conn.(net.PacketConn); ok { if isPacketConn(co.Conn) {
for { for {
r, err = co.ReadMsg() r, err = co.ReadMsg()
// Ignore replies with mismatched IDs because they might be // Ignore replies with mismatched IDs because they might be
@ -259,15 +279,8 @@ func (co *Conn) ReadMsg() (*Msg, error) {
return m, err return m, err
} }
if t := m.IsTsig(); t != nil { if t := m.IsTsig(); t != nil {
if co.TsigProvider != nil {
err = tsigVerifyProvider(p, co.TsigProvider, co.tsigRequestMAC, false)
} else {
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
return m, ErrSecret
}
// Need to work on the original message p, as that was used to calculate the tsig. // Need to work on the original message p, as that was used to calculate the tsig.
err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false) err = TsigVerifyWithProvider(p, co.tsigProvider(), co.tsigRequestMAC, false)
}
} }
return m, err return m, err
} }
@ -282,7 +295,7 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
err error err error
) )
if _, ok := co.Conn.(net.PacketConn); ok { if isPacketConn(co.Conn) {
if co.UDPSize > MinMsgSize { if co.UDPSize > MinMsgSize {
p = make([]byte, co.UDPSize) p = make([]byte, co.UDPSize)
} else { } else {
@ -322,7 +335,7 @@ func (co *Conn) Read(p []byte) (n int, err error) {
return 0, ErrConnEmpty return 0, ErrConnEmpty
} }
if _, ok := co.Conn.(net.PacketConn); ok { if isPacketConn(co.Conn) {
// UDP connection // UDP connection
return co.Conn.Read(p) return co.Conn.Read(p)
} }
@ -344,17 +357,8 @@ func (co *Conn) Read(p []byte) (n int, err error) {
func (co *Conn) WriteMsg(m *Msg) (err error) { func (co *Conn) WriteMsg(m *Msg) (err error) {
var out []byte var out []byte
if t := m.IsTsig(); t != nil { if t := m.IsTsig(); t != nil {
mac := "" // Set tsigRequestMAC for the next read, although only used in zone transfers.
if co.TsigProvider != nil { out, co.tsigRequestMAC, err = TsigGenerateWithProvider(m, co.tsigProvider(), co.tsigRequestMAC, false)
out, mac, err = tsigGenerateProvider(m, co.TsigProvider, co.tsigRequestMAC, false)
} else {
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
return ErrSecret
}
out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
}
// Set for the next read, although only used in zone transfers
co.tsigRequestMAC = mac
} else { } else {
out, err = m.Pack() out, err = m.Pack()
} }
@ -371,7 +375,7 @@ func (co *Conn) Write(p []byte) (int, error) {
return 0, &Error{err: "message too large"} return 0, &Error{err: "message too large"}
} }
if _, ok := co.Conn.(net.PacketConn); ok { if isPacketConn(co.Conn) {
return co.Conn.Write(p) return co.Conn.Write(p)
} }

View File

@ -218,6 +218,11 @@ func IsDomainName(s string) (labels int, ok bool) {
wasDot = false wasDot = false
case '.': case '.':
if i == 0 && len(s) > 1 {
// leading dots are not legal except for the root zone
return labels, false
}
if wasDot { if wasDot {
// two dots back to back is not legal // two dots back to back is not legal
return labels, false return labels, false

View File

@ -65,6 +65,9 @@ var AlgorithmToString = map[uint8]string{
} }
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's. // AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
// For newer algorithm that do their own hashing (i.e. ED25519) the returned value
// is 0, implying no (external) hashing should occur. The non-exported identityHash is then
// used.
var AlgorithmToHash = map[uint8]crypto.Hash{ var AlgorithmToHash = map[uint8]crypto.Hash{
RSAMD5: crypto.MD5, // Deprecated in RFC 6725 RSAMD5: crypto.MD5, // Deprecated in RFC 6725
DSA: crypto.SHA1, DSA: crypto.SHA1,
@ -74,7 +77,7 @@ var AlgorithmToHash = map[uint8]crypto.Hash{
ECDSAP256SHA256: crypto.SHA256, ECDSAP256SHA256: crypto.SHA256,
ECDSAP384SHA384: crypto.SHA384, ECDSAP384SHA384: crypto.SHA384,
RSASHA512: crypto.SHA512, RSASHA512: crypto.SHA512,
ED25519: crypto.Hash(0), ED25519: 0,
} }
// DNSSEC hashing algorithm codes. // DNSSEC hashing algorithm codes.
@ -137,12 +140,12 @@ func (k *DNSKEY) KeyTag() uint16 {
var keytag int var keytag int
switch k.Algorithm { switch k.Algorithm {
case RSAMD5: case RSAMD5:
// Look at the bottom two bytes of the modules, which the last
// item in the pubkey.
// This algorithm has been deprecated, but keep this key-tag calculation. // This algorithm has been deprecated, but keep this key-tag calculation.
// Look at the bottom two bytes of the modules, which the last item in the pubkey.
// See https://www.rfc-editor.org/errata/eid193 .
modulus, _ := fromBase64([]byte(k.PublicKey)) modulus, _ := fromBase64([]byte(k.PublicKey))
if len(modulus) > 1 { if len(modulus) > 1 {
x := binary.BigEndian.Uint16(modulus[len(modulus)-2:]) x := binary.BigEndian.Uint16(modulus[len(modulus)-3:])
keytag = int(x) keytag = int(x)
} }
default: default:
@ -296,35 +299,20 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
return err return err
} }
hash, ok := AlgorithmToHash[rr.Algorithm] h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
if !ok {
return ErrAlg
}
switch rr.Algorithm {
case ED25519:
// ed25519 signs the raw message and performs hashing internally.
// All other supported signature schemes operate over the pre-hashed
// message, and thus ed25519 must be handled separately here.
//
// The raw message is passed directly into sign and crypto.Hash(0) is
// used to signal to the crypto.Signer that the data has not been hashed.
signature, err := sign(k, append(signdata, wire...), crypto.Hash(0), rr.Algorithm)
if err != nil { if err != nil {
return err return err
} }
rr.Signature = toBase64(signature) switch rr.Algorithm {
return nil
case RSAMD5, DSA, DSANSEC3SHA1: case RSAMD5, DSA, DSANSEC3SHA1:
// See RFC 6944. // See RFC 6944.
return ErrAlg return ErrAlg
default: default:
h := hash.New()
h.Write(signdata) h.Write(signdata)
h.Write(wire) h.Write(wire)
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm) signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
if err != nil { if err != nil {
return err return err
} }
@ -341,7 +329,7 @@ func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte,
} }
switch alg { switch alg {
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512: case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, ED25519:
return signature, nil return signature, nil
case ECDSAP256SHA256, ECDSAP384SHA384: case ECDSAP256SHA256, ECDSAP384SHA384:
ecdsaSignature := &struct { ecdsaSignature := &struct {
@ -362,8 +350,6 @@ func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte,
signature := intToBytes(ecdsaSignature.R, intlen) signature := intToBytes(ecdsaSignature.R, intlen)
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...) signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
return signature, nil return signature, nil
case ED25519:
return signature, nil
default: default:
return nil, ErrAlg return nil, ErrAlg
} }
@ -437,9 +423,9 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
// remove the domain name and assume its ours? // remove the domain name and assume its ours?
} }
hash, ok := AlgorithmToHash[rr.Algorithm] h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
if !ok { if err != nil {
return ErrAlg return err
} }
switch rr.Algorithm { switch rr.Algorithm {
@ -450,10 +436,9 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
return ErrKey return ErrKey
} }
h := hash.New()
h.Write(signeddata) h.Write(signeddata)
h.Write(wire) h.Write(wire)
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf) return rsa.VerifyPKCS1v15(pubkey, cryptohash, h.Sum(nil), sigbuf)
case ECDSAP256SHA256, ECDSAP384SHA384: case ECDSAP256SHA256, ECDSAP384SHA384:
pubkey := k.publicKeyECDSA() pubkey := k.publicKeyECDSA()
@ -465,7 +450,6 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2]) r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:]) s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
h := hash.New()
h.Write(signeddata) h.Write(signeddata)
h.Write(wire) h.Write(wire)
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) { if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {

2
vendor/github.com/miekg/dns/doc.go generated vendored
View File

@ -251,7 +251,7 @@ information.
EDNS0 EDNS0
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by
RFC 6891. It defines an new RR type, the OPT RR, which is then completely RFC 6891. It defines a new RR type, the OPT RR, which is then completely
abused. abused.
Basic use pattern for creating an (empty) OPT RR: Basic use pattern for creating an (empty) OPT RR:

16
vendor/github.com/miekg/dns/edns.go generated vendored
View File

@ -584,14 +584,17 @@ func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
type EDNS0_EXPIRE struct { type EDNS0_EXPIRE struct {
Code uint16 // Always EDNS0EXPIRE Code uint16 // Always EDNS0EXPIRE
Expire uint32 Expire uint32
Empty bool // Empty is used to signal an empty Expire option in a backwards compatible way, it's not used on the wire.
} }
// Option implements the EDNS0 interface. // Option implements the EDNS0 interface.
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE } func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) } func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire, e.Empty} }
func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire} }
func (e *EDNS0_EXPIRE) pack() ([]byte, error) { func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
if e.Empty {
return []byte{}, nil
}
b := make([]byte, 4) b := make([]byte, 4)
binary.BigEndian.PutUint32(b, e.Expire) binary.BigEndian.PutUint32(b, e.Expire)
return b, nil return b, nil
@ -600,15 +603,24 @@ func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
func (e *EDNS0_EXPIRE) unpack(b []byte) error { func (e *EDNS0_EXPIRE) unpack(b []byte) error {
if len(b) == 0 { if len(b) == 0 {
// zero-length EXPIRE query, see RFC 7314 Section 2 // zero-length EXPIRE query, see RFC 7314 Section 2
e.Empty = true
return nil return nil
} }
if len(b) < 4 { if len(b) < 4 {
return ErrBuf return ErrBuf
} }
e.Expire = binary.BigEndian.Uint32(b) e.Expire = binary.BigEndian.Uint32(b)
e.Empty = false
return nil return nil
} }
func (e *EDNS0_EXPIRE) String() (s string) {
if e.Empty {
return ""
}
return strconv.FormatUint(uint64(e.Expire), 10)
}
// The EDNS0_LOCAL option is used for local/experimental purposes. The option // The EDNS0_LOCAL option is used for local/experimental purposes. The option
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND] // code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
// (RFC6891), although any unassigned code can actually be used. The content of // (RFC6891), although any unassigned code can actually be used. The content of

31
vendor/github.com/miekg/dns/hash.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
package dns
import (
"bytes"
"crypto"
"hash"
)
// identityHash will not hash, it only buffers the data written into it and returns it as-is.
type identityHash struct {
b *bytes.Buffer
}
// Implement the hash.Hash interface.
func (i identityHash) Write(b []byte) (int, error) { return i.b.Write(b) }
func (i identityHash) Size() int { return i.b.Len() }
func (i identityHash) BlockSize() int { return 1024 }
func (i identityHash) Reset() { i.b.Reset() }
func (i identityHash) Sum(b []byte) []byte { return append(b, i.b.Bytes()...) }
func hashFromAlgorithm(alg uint8) (hash.Hash, crypto.Hash, error) {
hashnumber, ok := AlgorithmToHash[alg]
if !ok {
return nil, 0, ErrAlg
}
if hashnumber == 0 {
return identityHash{b: &bytes.Buffer{}}, hashnumber, nil
}
return hashnumber.New(), hashnumber, nil
}

14
vendor/github.com/miekg/dns/msg.go generated vendored
View File

@ -265,6 +265,11 @@ loop:
wasDot = false wasDot = false
case '.': case '.':
if i == 0 && len(s) > 1 {
// leading dots are not legal except for the root zone
return len(msg), ErrRdata
}
if wasDot { if wasDot {
// two dots back to back is not legal // two dots back to back is not legal
return len(msg), ErrRdata return len(msg), ErrRdata
@ -901,6 +906,11 @@ func (dns *Msg) String() string {
s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", " s += "ANSWER: " + strconv.Itoa(len(dns.Answer)) + ", "
s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", " s += "AUTHORITY: " + strconv.Itoa(len(dns.Ns)) + ", "
s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n" s += "ADDITIONAL: " + strconv.Itoa(len(dns.Extra)) + "\n"
opt := dns.IsEdns0()
if opt != nil {
// OPT PSEUDOSECTION
s += opt.String() + "\n"
}
if len(dns.Question) > 0 { if len(dns.Question) > 0 {
s += "\n;; QUESTION SECTION:\n" s += "\n;; QUESTION SECTION:\n"
for _, r := range dns.Question { for _, r := range dns.Question {
@ -923,10 +933,10 @@ func (dns *Msg) String() string {
} }
} }
} }
if len(dns.Extra) > 0 { if len(dns.Extra) > 0 && (opt == nil || len(dns.Extra) > 1) {
s += "\n;; ADDITIONAL SECTION:\n" s += "\n;; ADDITIONAL SECTION:\n"
for _, r := range dns.Extra { for _, r := range dns.Extra {
if r != nil { if r != nil && r.Header().Rrtype != TypeOPT {
s += r.String() + "\n" s += r.String() + "\n"
} }
} }

View File

@ -476,7 +476,7 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
length, window, lastwindow := 0, 0, -1 length, window, lastwindow := 0, 0, -1
for off < len(msg) { for off < len(msg) {
if off+2 > len(msg) { if off+2 > len(msg) {
return nsec, len(msg), &Error{err: "overflow unpacking nsecx"} return nsec, len(msg), &Error{err: "overflow unpacking NSEC(3)"}
} }
window = int(msg[off]) window = int(msg[off])
length = int(msg[off+1]) length = int(msg[off+1])
@ -484,17 +484,17 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
if window <= lastwindow { if window <= lastwindow {
// RFC 4034: Blocks are present in the NSEC RR RDATA in // RFC 4034: Blocks are present in the NSEC RR RDATA in
// increasing numerical order. // increasing numerical order.
return nsec, len(msg), &Error{err: "out of order NSEC block"} return nsec, len(msg), &Error{err: "out of order NSEC(3) block in type bitmap"}
} }
if length == 0 { if length == 0 {
// RFC 4034: Blocks with no types present MUST NOT be included. // RFC 4034: Blocks with no types present MUST NOT be included.
return nsec, len(msg), &Error{err: "empty NSEC block"} return nsec, len(msg), &Error{err: "empty NSEC(3) block in type bitmap"}
} }
if length > 32 { if length > 32 {
return nsec, len(msg), &Error{err: "NSEC block too long"} return nsec, len(msg), &Error{err: "NSEC(3) block too long in type bitmap"}
} }
if off+length > len(msg) { if off+length > len(msg) {
return nsec, len(msg), &Error{err: "overflowing NSEC block"} return nsec, len(msg), &Error{err: "overflowing NSEC(3) block in type bitmap"}
} }
// Walk the bytes in the window and extract the type bits // Walk the bytes in the window and extract the type bits
@ -558,6 +558,16 @@ func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
if len(bitmap) == 0 { if len(bitmap) == 0 {
return off, nil return off, nil
} }
if off > len(msg) {
return off, &Error{err: "overflow packing nsec"}
}
toZero := msg[off:]
if maxLen := typeBitMapLen(bitmap); maxLen < len(toZero) {
toZero = toZero[:maxLen]
}
for i := range toZero {
toZero[i] = 0
}
var lastwindow, lastlength uint16 var lastwindow, lastlength uint16
for _, t := range bitmap { for _, t := range bitmap {
window := t / 256 window := t / 256

View File

@ -71,7 +71,7 @@ type response struct {
tsigTimersOnly bool tsigTimersOnly bool
tsigStatus error tsigStatus error
tsigRequestMAC string tsigRequestMAC string
tsigSecret map[string]string // the tsig secrets tsigProvider TsigProvider
udp net.PacketConn // i/o connection if UDP was used udp net.PacketConn // i/o connection if UDP was used
tcp net.Conn // i/o connection if TCP was used tcp net.Conn // i/o connection if TCP was used
udpSession *SessionUDP // oob data to get egress interface right udpSession *SessionUDP // oob data to get egress interface right
@ -211,6 +211,8 @@ type Server struct {
WriteTimeout time.Duration WriteTimeout time.Duration
// TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966). // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
IdleTimeout func() time.Duration IdleTimeout func() time.Duration
// An implementation of the TsigProvider interface. If defined it replaces TsigSecret and is used for all TSIG operations.
TsigProvider TsigProvider
// Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2). // Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
TsigSecret map[string]string TsigSecret map[string]string
// If NotifyStartedFunc is set it is called once the server has started listening. // If NotifyStartedFunc is set it is called once the server has started listening.
@ -238,6 +240,16 @@ type Server struct {
udpPool sync.Pool udpPool sync.Pool
} }
func (srv *Server) tsigProvider() TsigProvider {
if srv.TsigProvider != nil {
return srv.TsigProvider
}
if srv.TsigSecret != nil {
return tsigSecretProvider(srv.TsigSecret)
}
return nil
}
func (srv *Server) isStarted() bool { func (srv *Server) isStarted() bool {
srv.lock.RLock() srv.lock.RLock()
started := srv.started started := srv.started
@ -526,7 +538,7 @@ func (srv *Server) serveUDP(l net.PacketConn) error {
// Serve a new TCP connection. // Serve a new TCP connection.
func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) { func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
w := &response{tsigSecret: srv.TsigSecret, tcp: rw} w := &response{tsigProvider: srv.tsigProvider(), tcp: rw}
if srv.DecorateWriter != nil { if srv.DecorateWriter != nil {
w.writer = srv.DecorateWriter(w) w.writer = srv.DecorateWriter(w)
} else { } else {
@ -581,7 +593,7 @@ func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
// Serve a new UDP request. // Serve a new UDP request.
func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) { func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) {
w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: udpSession, pcSession: pcSession} w := &response{tsigProvider: srv.tsigProvider(), udp: u, udpSession: udpSession, pcSession: pcSession}
if srv.DecorateWriter != nil { if srv.DecorateWriter != nil {
w.writer = srv.DecorateWriter(w) w.writer = srv.DecorateWriter(w)
} else { } else {
@ -632,15 +644,11 @@ func (srv *Server) serveDNS(m []byte, w *response) {
} }
w.tsigStatus = nil w.tsigStatus = nil
if w.tsigSecret != nil { if w.tsigProvider != nil {
if t := req.IsTsig(); t != nil { if t := req.IsTsig(); t != nil {
if secret, ok := w.tsigSecret[t.Hdr.Name]; ok { w.tsigStatus = TsigVerifyWithProvider(m, w.tsigProvider, "", false)
w.tsigStatus = TsigVerify(m, secret, "", false)
} else {
w.tsigStatus = ErrSecret
}
w.tsigTimersOnly = false w.tsigTimersOnly = false
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC w.tsigRequestMAC = t.MAC
} }
} }
@ -718,9 +726,9 @@ func (w *response) WriteMsg(m *Msg) (err error) {
} }
var data []byte var data []byte
if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check) if w.tsigProvider != nil { // if no provider, dont check for the tsig (which is a longer check)
if t := m.IsTsig(); t != nil { if t := m.IsTsig(); t != nil {
data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly) data, w.tsigRequestMAC, err = TsigGenerateWithProvider(m, w.tsigProvider, w.tsigRequestMAC, w.tsigTimersOnly)
if err != nil { if err != nil {
return err return err
} }

51
vendor/github.com/miekg/dns/sig0.go generated vendored
View File

@ -3,6 +3,7 @@ package dns
import ( import (
"crypto" "crypto"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa" "crypto/rsa"
"encoding/binary" "encoding/binary"
"math/big" "math/big"
@ -38,18 +39,17 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
} }
buf = buf[:off:cap(buf)] buf = buf[:off:cap(buf)]
hash, ok := AlgorithmToHash[rr.Algorithm] h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
if !ok { if err != nil {
return nil, ErrAlg return nil, err
} }
hasher := hash.New()
// Write SIG rdata // Write SIG rdata
hasher.Write(buf[len(mbuf)+1+2+2+4+2:]) h.Write(buf[len(mbuf)+1+2+2+4+2:])
// Write message // Write message
hasher.Write(buf[:len(mbuf)]) h.Write(buf[:len(mbuf)])
signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm) signature, err := sign(k, h.Sum(nil), cryptohash, rr.Algorithm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -82,20 +82,10 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
return ErrKey return ErrKey
} }
var hash crypto.Hash h, cryptohash, err := hashFromAlgorithm(rr.Algorithm)
switch rr.Algorithm { if err != nil {
case RSASHA1: return err
hash = crypto.SHA1
case RSASHA256, ECDSAP256SHA256:
hash = crypto.SHA256
case ECDSAP384SHA384:
hash = crypto.SHA384
case RSASHA512:
hash = crypto.SHA512
default:
return ErrAlg
} }
hasher := hash.New()
buflen := len(buf) buflen := len(buf)
qdc := binary.BigEndian.Uint16(buf[4:]) qdc := binary.BigEndian.Uint16(buf[4:])
@ -103,7 +93,6 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
auc := binary.BigEndian.Uint16(buf[8:]) auc := binary.BigEndian.Uint16(buf[8:])
adc := binary.BigEndian.Uint16(buf[10:]) adc := binary.BigEndian.Uint16(buf[10:])
offset := headerSize offset := headerSize
var err error
for i := uint16(0); i < qdc && offset < buflen; i++ { for i := uint16(0); i < qdc && offset < buflen; i++ {
_, offset, err = UnpackDomainName(buf, offset) _, offset, err = UnpackDomainName(buf, offset)
if err != nil { if err != nil {
@ -166,21 +155,21 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
return &Error{err: "signer name doesn't match key name"} return &Error{err: "signer name doesn't match key name"}
} }
sigend := offset sigend := offset
hasher.Write(buf[sigstart:sigend]) h.Write(buf[sigstart:sigend])
hasher.Write(buf[:10]) h.Write(buf[:10])
hasher.Write([]byte{ h.Write([]byte{
byte((adc - 1) << 8), byte((adc - 1) << 8),
byte(adc - 1), byte(adc - 1),
}) })
hasher.Write(buf[12:bodyend]) h.Write(buf[12:bodyend])
hashed := hasher.Sum(nil) hashed := h.Sum(nil)
sig := buf[sigend:] sig := buf[sigend:]
switch k.Algorithm { switch k.Algorithm {
case RSASHA1, RSASHA256, RSASHA512: case RSASHA1, RSASHA256, RSASHA512:
pk := k.publicKeyRSA() pk := k.publicKeyRSA()
if pk != nil { if pk != nil {
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig) return rsa.VerifyPKCS1v15(pk, cryptohash, hashed, sig)
} }
case ECDSAP256SHA256, ECDSAP384SHA384: case ECDSAP256SHA256, ECDSAP384SHA384:
pk := k.publicKeyECDSA() pk := k.publicKeyECDSA()
@ -192,6 +181,14 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
} }
return ErrSig return ErrSig
} }
case ED25519:
pk := k.publicKeyED25519()
if pk != nil {
if ed25519.Verify(pk, hashed, sig) {
return nil
}
return ErrSig
}
} }
return ErrKeyAlg return ErrKeyAlg
} }

326
vendor/github.com/miekg/dns/svcb.go generated vendored
View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"net" "net"
"sort" "sort"
"strconv" "strconv"
@ -13,15 +14,17 @@ import (
// SVCBKey is the type of the keys used in the SVCB RR. // SVCBKey is the type of the keys used in the SVCB RR.
type SVCBKey uint16 type SVCBKey uint16
// Keys defined in draft-ietf-dnsop-svcb-https-01 Section 12.3.2. // Keys defined in draft-ietf-dnsop-svcb-https-08 Section 14.3.2.
const ( const (
SVCB_MANDATORY SVCBKey = 0 SVCB_MANDATORY SVCBKey = iota
SVCB_ALPN SVCBKey = 1 SVCB_ALPN
SVCB_NO_DEFAULT_ALPN SVCBKey = 2 SVCB_NO_DEFAULT_ALPN
SVCB_PORT SVCBKey = 3 SVCB_PORT
SVCB_IPV4HINT SVCBKey = 4 SVCB_IPV4HINT
SVCB_ECHCONFIG SVCBKey = 5 SVCB_ECHCONFIG
SVCB_IPV6HINT SVCBKey = 6 SVCB_IPV6HINT
SVCB_DOHPATH // draft-ietf-add-svcb-dns-02 Section 9
svcb_RESERVED SVCBKey = 65535 svcb_RESERVED SVCBKey = 65535
) )
@ -31,8 +34,9 @@ var svcbKeyToStringMap = map[SVCBKey]string{
SVCB_NO_DEFAULT_ALPN: "no-default-alpn", SVCB_NO_DEFAULT_ALPN: "no-default-alpn",
SVCB_PORT: "port", SVCB_PORT: "port",
SVCB_IPV4HINT: "ipv4hint", SVCB_IPV4HINT: "ipv4hint",
SVCB_ECHCONFIG: "echconfig", SVCB_ECHCONFIG: "ech",
SVCB_IPV6HINT: "ipv6hint", SVCB_IPV6HINT: "ipv6hint",
SVCB_DOHPATH: "dohpath",
} }
var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap) var svcbStringToKeyMap = reverseSVCBKeyMap(svcbKeyToStringMap)
@ -167,10 +171,14 @@ func (rr *SVCB) parse(c *zlexer, o string) *ParseError {
} }
l, _ = c.Next() l, _ = c.Next()
} }
// "In AliasMode, records SHOULD NOT include any SvcParams, and recipients MUST
// ignore any SvcParams that are present."
// However, we don't check rr.Priority == 0 && len(xs) > 0 here
// It is the responsibility of the user of the library to check this.
// This is to encourage the fixing of the source of this error.
rr.Value = xs rr.Value = xs
if rr.Priority == 0 && len(xs) > 0 {
return &ParseError{l.token, "SVCB aliasform can't have values", l}
}
return nil return nil
} }
@ -191,6 +199,8 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
return new(SVCBECHConfig) return new(SVCBECHConfig)
case SVCB_IPV6HINT: case SVCB_IPV6HINT:
return new(SVCBIPv6Hint) return new(SVCBIPv6Hint)
case SVCB_DOHPATH:
return new(SVCBDoHPath)
case svcb_RESERVED: case svcb_RESERVED:
return nil return nil
default: default:
@ -200,16 +210,24 @@ func makeSVCBKeyValue(key SVCBKey) SVCBKeyValue {
} }
} }
// SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-01). // SVCB RR. See RFC xxxx (https://tools.ietf.org/html/draft-ietf-dnsop-svcb-https-08).
//
// NOTE: The HTTPS/SVCB RFCs are in the draft stage.
// The API, including constants and types related to SVCBKeyValues, may
// change in future versions in accordance with the latest drafts.
type SVCB struct { type SVCB struct {
Hdr RR_Header Hdr RR_Header
Priority uint16 Priority uint16 // If zero, Value must be empty or discarded by the user of this library
Target string `dns:"domain-name"` Target string `dns:"domain-name"`
Value []SVCBKeyValue `dns:"pairs"` // Value must be empty if Priority is zero. Value []SVCBKeyValue `dns:"pairs"`
} }
// HTTPS RR. Everything valid for SVCB applies to HTTPS as well. // HTTPS RR. Everything valid for SVCB applies to HTTPS as well.
// Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols. // Except that the HTTPS record is intended for use with the HTTP and HTTPS protocols.
//
// NOTE: The HTTPS/SVCB RFCs are in the draft stage.
// The API, including constants and types related to SVCBKeyValues, may
// change in future versions in accordance with the latest drafts.
type HTTPS struct { type HTTPS struct {
SVCB SVCB
} }
@ -235,15 +253,29 @@ type SVCBKeyValue interface {
} }
// SVCBMandatory pair adds to required keys that must be interpreted for the RR // SVCBMandatory pair adds to required keys that must be interpreted for the RR
// to be functional. // to be functional. If ignored, the whole RRSet must be ignored.
// "port" and "no-default-alpn" are mandatory by default if present,
// so they shouldn't be included here.
//
// It is incumbent upon the user of this library to reject the RRSet if
// or avoid constructing such an RRSet that:
// - "mandatory" is included as one of the keys of mandatory
// - no key is listed multiple times in mandatory
// - all keys listed in mandatory are present
// - escape sequences are not used in mandatory
// - mandatory, when present, lists at least one key
//
// Basic use pattern for creating a mandatory option: // Basic use pattern for creating a mandatory option:
// //
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}} // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
// e := new(dns.SVCBMandatory) // e := new(dns.SVCBMandatory)
// e.Code = []uint16{65403} // e.Code = []uint16{dns.SVCB_ALPN}
// s.Value = append(s.Value, e) // s.Value = append(s.Value, e)
// t := new(dns.SVCBAlpn)
// t.Alpn = []string{"xmpp-client"}
// s.Value = append(s.Value, t)
type SVCBMandatory struct { type SVCBMandatory struct {
Code []SVCBKey // Must not include mandatory Code []SVCBKey
} }
func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY } func (*SVCBMandatory) Key() SVCBKey { return SVCB_MANDATORY }
@ -302,7 +334,8 @@ func (s *SVCBMandatory) copy() SVCBKeyValue {
} }
// SVCBAlpn pair is used to list supported connection protocols. // SVCBAlpn pair is used to list supported connection protocols.
// Protocol ids can be found at: // The user of this library must ensure that at least one protocol is listed when alpn is present.
// Protocol IDs can be found at:
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
// Basic use pattern for creating an alpn option: // Basic use pattern for creating an alpn option:
// //
@ -310,13 +343,57 @@ func (s *SVCBMandatory) copy() SVCBKeyValue {
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET} // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
// e := new(dns.SVCBAlpn) // e := new(dns.SVCBAlpn)
// e.Alpn = []string{"h2", "http/1.1"} // e.Alpn = []string{"h2", "http/1.1"}
// h.Value = append(o.Value, e) // h.Value = append(h.Value, e)
type SVCBAlpn struct { type SVCBAlpn struct {
Alpn []string Alpn []string
} }
func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN } func (*SVCBAlpn) Key() SVCBKey { return SVCB_ALPN }
func (s *SVCBAlpn) String() string { return strings.Join(s.Alpn, ",") }
func (s *SVCBAlpn) String() string {
// An ALPN value is a comma-separated list of values, each of which can be
// an arbitrary binary value. In order to allow parsing, the comma and
// backslash characters are themselves excaped.
//
// However, this escaping is done in addition to the normal escaping which
// happens in zone files, meaning that these values must be
// double-escaped. This looks terrible, so if you see a never-ending
// sequence of backslash in a zone file this may be why.
//
// https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-08#appendix-A.1
var str strings.Builder
for i, alpn := range s.Alpn {
// 4*len(alpn) is the worst case where we escape every character in the alpn as \123, plus 1 byte for the ',' separating the alpn from others
str.Grow(4*len(alpn) + 1)
if i > 0 {
str.WriteByte(',')
}
for j := 0; j < len(alpn); j++ {
e := alpn[j]
if ' ' > e || e > '~' {
str.WriteString(escapeByte(e))
continue
}
switch e {
// We escape a few characters which may confuse humans or parsers.
case '"', ';', ' ':
str.WriteByte('\\')
str.WriteByte(e)
// The comma and backslash characters themselves must be
// doubly-escaped. We use `\\` for the first backslash and
// the escaped numeric value for the other value. We especially
// don't want a comma in the output.
case ',':
str.WriteString(`\\\044`)
case '\\':
str.WriteString(`\\\092`)
default:
str.WriteByte(e)
}
}
}
return str.String()
}
func (s *SVCBAlpn) pack() ([]byte, error) { func (s *SVCBAlpn) pack() ([]byte, error) {
// Liberally estimate the size of an alpn as 10 octets // Liberally estimate the size of an alpn as 10 octets
@ -351,7 +428,47 @@ func (s *SVCBAlpn) unpack(b []byte) error {
} }
func (s *SVCBAlpn) parse(b string) error { func (s *SVCBAlpn) parse(b string) error {
s.Alpn = strings.Split(b, ",") if len(b) == 0 {
s.Alpn = []string{}
return nil
}
alpn := []string{}
a := []byte{}
for p := 0; p < len(b); {
c, q := nextByte(b, p)
if q == 0 {
return errors.New("dns: svcbalpn: unterminated escape")
}
p += q
// If we find a comma, we have finished reading an alpn.
if c == ',' {
if len(a) == 0 {
return errors.New("dns: svcbalpn: empty protocol identifier")
}
alpn = append(alpn, string(a))
a = []byte{}
continue
}
// If it's a backslash, we need to handle a comma-separated list.
if c == '\\' {
dc, dq := nextByte(b, p)
if dq == 0 {
return errors.New("dns: svcbalpn: unterminated escape decoding comma-separated list")
}
if dc != '\\' && dc != ',' {
return errors.New("dns: svcbalpn: bad escaped character decoding comma-separated list")
}
p += dq
c = dc
}
a = append(a, c)
}
// Add the final alpn.
if len(a) == 0 {
return errors.New("dns: svcbalpn: last protocol identifier empty")
}
s.Alpn = append(alpn, string(a))
return nil return nil
} }
@ -370,9 +487,13 @@ func (s *SVCBAlpn) copy() SVCBKeyValue {
} }
// SVCBNoDefaultAlpn pair signifies no support for default connection protocols. // SVCBNoDefaultAlpn pair signifies no support for default connection protocols.
// Should be used in conjunction with alpn.
// Basic use pattern for creating a no-default-alpn option: // Basic use pattern for creating a no-default-alpn option:
// //
// s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}} // s := &dns.SVCB{Hdr: dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}}
// t := new(dns.SVCBAlpn)
// t.Alpn = []string{"xmpp-client"}
// s.Value = append(s.Value, t)
// e := new(dns.SVCBNoDefaultAlpn) // e := new(dns.SVCBNoDefaultAlpn)
// s.Value = append(s.Value, e) // s.Value = append(s.Value, e)
type SVCBNoDefaultAlpn struct{} type SVCBNoDefaultAlpn struct{}
@ -385,14 +506,14 @@ func (*SVCBNoDefaultAlpn) len() int { return 0 }
func (*SVCBNoDefaultAlpn) unpack(b []byte) error { func (*SVCBNoDefaultAlpn) unpack(b []byte) error {
if len(b) != 0 { if len(b) != 0 {
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value") return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
} }
return nil return nil
} }
func (*SVCBNoDefaultAlpn) parse(b string) error { func (*SVCBNoDefaultAlpn) parse(b string) error {
if b != "" { if b != "" {
return errors.New("dns: svcbnodefaultalpn: no_default_alpn must have no value") return errors.New("dns: svcbnodefaultalpn: no-default-alpn must have no value")
} }
return nil return nil
} }
@ -523,7 +644,7 @@ func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
} }
// SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx]. // SVCBECHConfig pair contains the ECHConfig structure defined in draft-ietf-tls-esni [RFC xxxx].
// Basic use pattern for creating an echconfig option: // Basic use pattern for creating an ech option:
// //
// h := new(dns.HTTPS) // h := new(dns.HTTPS)
// h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET} // h.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeHTTPS, Class: dns.ClassINET}
@ -531,7 +652,7 @@ func (s *SVCBIPv4Hint) copy() SVCBKeyValue {
// e.ECH = []byte{0xfe, 0x08, ...} // e.ECH = []byte{0xfe, 0x08, ...}
// h.Value = append(h.Value, e) // h.Value = append(h.Value, e)
type SVCBECHConfig struct { type SVCBECHConfig struct {
ECH []byte ECH []byte // Specifically ECHConfigList including the redundant length prefix
} }
func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG } func (*SVCBECHConfig) Key() SVCBKey { return SVCB_ECHCONFIG }
@ -555,7 +676,7 @@ func (s *SVCBECHConfig) unpack(b []byte) error {
func (s *SVCBECHConfig) parse(b string) error { func (s *SVCBECHConfig) parse(b string) error {
x, err := fromBase64([]byte(b)) x, err := fromBase64([]byte(b))
if err != nil { if err != nil {
return errors.New("dns: svcbechconfig: bad base64 echconfig") return errors.New("dns: svcbech: bad base64 ech")
} }
s.ECH = x s.ECH = x
return nil return nil
@ -618,9 +739,6 @@ func (s *SVCBIPv6Hint) String() string {
} }
func (s *SVCBIPv6Hint) parse(b string) error { func (s *SVCBIPv6Hint) parse(b string) error {
if strings.Contains(b, ".") {
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4")
}
str := strings.Split(b, ",") str := strings.Split(b, ",")
dst := make([]net.IP, len(str)) dst := make([]net.IP, len(str))
for i, e := range str { for i, e := range str {
@ -628,6 +746,9 @@ func (s *SVCBIPv6Hint) parse(b string) error {
if ip == nil { if ip == nil {
return errors.New("dns: svcbipv6hint: bad ip") return errors.New("dns: svcbipv6hint: bad ip")
} }
if ip.To4() != nil {
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4-mapped-ipv6")
}
dst[i] = ip dst[i] = ip
} }
s.Hint = dst s.Hint = dst
@ -645,6 +766,54 @@ func (s *SVCBIPv6Hint) copy() SVCBKeyValue {
} }
} }
// SVCBDoHPath pair is used to indicate the URI template that the
// clients may use to construct a DNS over HTTPS URI.
//
// See RFC xxxx (https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02)
// and RFC yyyy (https://datatracker.ietf.org/doc/html/draft-ietf-add-ddr-06).
//
// A basic example of using the dohpath option together with the alpn
// option to indicate support for DNS over HTTPS on a certain path:
//
// s := new(dns.SVCB)
// s.Hdr = dns.RR_Header{Name: ".", Rrtype: dns.TypeSVCB, Class: dns.ClassINET}
// e := new(dns.SVCBAlpn)
// e.Alpn = []string{"h2", "h3"}
// p := new(dns.SVCBDoHPath)
// p.Template = "/dns-query{?dns}"
// s.Value = append(s.Value, e, p)
//
// The parsing currently doesn't validate that Template is a valid
// RFC 6570 URI template.
type SVCBDoHPath struct {
Template string
}
func (*SVCBDoHPath) Key() SVCBKey { return SVCB_DOHPATH }
func (s *SVCBDoHPath) String() string { return svcbParamToStr([]byte(s.Template)) }
func (s *SVCBDoHPath) len() int { return len(s.Template) }
func (s *SVCBDoHPath) pack() ([]byte, error) { return []byte(s.Template), nil }
func (s *SVCBDoHPath) unpack(b []byte) error {
s.Template = string(b)
return nil
}
func (s *SVCBDoHPath) parse(b string) error {
template, err := svcbParseParam(b)
if err != nil {
return fmt.Errorf("dns: svcbdohpath: %w", err)
}
s.Template = string(template)
return nil
}
func (s *SVCBDoHPath) copy() SVCBKeyValue {
return &SVCBDoHPath{
Template: s.Template,
}
}
// SVCBLocal pair is intended for experimental/private use. The key is recommended // SVCBLocal pair is intended for experimental/private use. The key is recommended
// to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER]. // to be in the range [SVCB_PRIVATE_LOWER, SVCB_PRIVATE_UPPER].
// Basic use pattern for creating a keyNNNNN option: // Basic use pattern for creating a keyNNNNN option:
@ -661,6 +830,7 @@ type SVCBLocal struct {
} }
func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode } func (s *SVCBLocal) Key() SVCBKey { return s.KeyCode }
func (s *SVCBLocal) String() string { return svcbParamToStr(s.Data) }
func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil } func (s *SVCBLocal) pack() ([]byte, error) { return append([]byte(nil), s.Data...), nil }
func (s *SVCBLocal) len() int { return len(s.Data) } func (s *SVCBLocal) len() int { return len(s.Data) }
@ -669,50 +839,10 @@ func (s *SVCBLocal) unpack(b []byte) error {
return nil return nil
} }
func (s *SVCBLocal) String() string {
var str strings.Builder
str.Grow(4 * len(s.Data))
for _, e := range s.Data {
if ' ' <= e && e <= '~' {
switch e {
case '"', ';', ' ', '\\':
str.WriteByte('\\')
str.WriteByte(e)
default:
str.WriteByte(e)
}
} else {
str.WriteString(escapeByte(e))
}
}
return str.String()
}
func (s *SVCBLocal) parse(b string) error { func (s *SVCBLocal) parse(b string) error {
data := make([]byte, 0, len(b)) data, err := svcbParseParam(b)
for i := 0; i < len(b); { if err != nil {
if b[i] != '\\' { return fmt.Errorf("dns: svcblocal: svcb private/experimental key %w", err)
data = append(data, b[i])
i++
continue
}
if i+1 == len(b) {
return errors.New("dns: svcblocal: svcb private/experimental key escape unterminated")
}
if isDigit(b[i+1]) {
if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
if err == nil {
i += 4
data = append(data, byte(a))
continue
}
}
return errors.New("dns: svcblocal: svcb private/experimental key bad escaped octet")
} else {
data = append(data, b[i+1])
i += 2
}
} }
s.Data = data s.Data = data
return nil return nil
@ -753,3 +883,53 @@ func areSVCBPairArraysEqual(a []SVCBKeyValue, b []SVCBKeyValue) bool {
} }
return true return true
} }
// svcbParamStr converts the value of an SVCB parameter into a DNS presentation-format string.
func svcbParamToStr(s []byte) string {
var str strings.Builder
str.Grow(4 * len(s))
for _, e := range s {
if ' ' <= e && e <= '~' {
switch e {
case '"', ';', ' ', '\\':
str.WriteByte('\\')
str.WriteByte(e)
default:
str.WriteByte(e)
}
} else {
str.WriteString(escapeByte(e))
}
}
return str.String()
}
// svcbParseParam parses a DNS presentation-format string into an SVCB parameter value.
func svcbParseParam(b string) ([]byte, error) {
data := make([]byte, 0, len(b))
for i := 0; i < len(b); {
if b[i] != '\\' {
data = append(data, b[i])
i++
continue
}
if i+1 == len(b) {
return nil, errors.New("escape unterminated")
}
if isDigit(b[i+1]) {
if i+3 < len(b) && isDigit(b[i+2]) && isDigit(b[i+3]) {
a, err := strconv.ParseUint(b[i+1:i+4], 10, 8)
if err == nil {
i += 4
data = append(data, byte(a))
continue
}
}
return nil, errors.New("bad escaped octet")
} else {
data = append(data, b[i+1])
i += 2
}
}
return data, nil
}

44
vendor/github.com/miekg/dns/tsig.go generated vendored
View File

@ -74,6 +74,24 @@ func (key tsigHMACProvider) Verify(msg []byte, t *TSIG) error {
return nil return nil
} }
type tsigSecretProvider map[string]string
func (ts tsigSecretProvider) Generate(msg []byte, t *TSIG) ([]byte, error) {
key, ok := ts[t.Hdr.Name]
if !ok {
return nil, ErrSecret
}
return tsigHMACProvider(key).Generate(msg, t)
}
func (ts tsigSecretProvider) Verify(msg []byte, t *TSIG) error {
key, ok := ts[t.Hdr.Name]
if !ok {
return ErrSecret
}
return tsigHMACProvider(key).Verify(msg, t)
}
// TSIG is the RR the holds the transaction signature of a message. // TSIG is the RR the holds the transaction signature of a message.
// See RFC 2845 and RFC 4635. // See RFC 2845 and RFC 4635.
type TSIG struct { type TSIG struct {
@ -140,18 +158,17 @@ type timerWireFmt struct {
} }
// TsigGenerate fills out the TSIG record attached to the message. // TsigGenerate fills out the TSIG record attached to the message.
// The message should contain // The message should contain a "stub" TSIG RR with the algorithm, key name
// a "stub" TSIG RR with the algorithm, key name (owner name of the RR), // (owner name of the RR), time fudge (defaults to 300 seconds) and the current
// time fudge (defaults to 300 seconds) and the current time // time The TSIG MAC is saved in that Tsig RR. When TsigGenerate is called for
// The TSIG MAC is saved in that Tsig RR. // the first time requestMAC should be set to the empty string and timersOnly to
// When TsigGenerate is called for the first time requestMAC is set to the empty string and // false.
// timersOnly is false.
// If something goes wrong an error is returned, otherwise it is nil.
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) { func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
return tsigGenerateProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly) return TsigGenerateWithProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly)
} }
func tsigGenerateProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) { // TsigGenerateWithProvider is similar to TsigGenerate, but allows for a custom TsigProvider.
func TsigGenerateWithProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) {
if m.IsTsig() == nil { if m.IsTsig() == nil {
panic("dns: TSIG not last RR in additional") panic("dns: TSIG not last RR in additional")
} }
@ -198,14 +215,15 @@ func tsigGenerateProvider(m *Msg, provider TsigProvider, requestMAC string, time
return mbuf, t.MAC, nil return mbuf, t.MAC, nil
} }
// TsigVerify verifies the TSIG on a message. // TsigVerify verifies the TSIG on a message. If the signature does not
// If the signature does not validate err contains the // validate the returned error contains the cause. If the signature is OK, the
// error, otherwise it is nil. // error is nil.
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error { func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix())) return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix()))
} }
func tsigVerifyProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error { // TsigVerifyWithProvider is similar to TsigVerify, but allows for a custom TsigProvider.
func TsigVerifyWithProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error {
return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix())) return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix()))
} }

View File

@ -3,7 +3,7 @@ package dns
import "fmt" import "fmt"
// Version is current version of this library. // Version is current version of this library.
var Version = v{1, 1, 45} var Version = v{1, 1, 50}
// v holds the version of this library. // v holds the version of this library.
type v struct { type v struct {

27
vendor/github.com/miekg/dns/xfr.go generated vendored
View File

@ -17,11 +17,22 @@ type Transfer struct {
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
TsigProvider TsigProvider // An implementation of the TsigProvider interface. If defined it replaces TsigSecret and is used for all TSIG operations.
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2) TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
tsigTimersOnly bool tsigTimersOnly bool
} }
// Think we need to away to stop the transfer func (t *Transfer) tsigProvider() TsigProvider {
if t.TsigProvider != nil {
return t.TsigProvider
}
if t.TsigSecret != nil {
return tsigSecretProvider(t.TsigSecret)
}
return nil
}
// TODO: Think we need to away to stop the transfer
// In performs an incoming transfer with the server in a. // In performs an incoming transfer with the server in a.
// If you would like to set the source IP, or some other attribute // If you would like to set the source IP, or some other attribute
@ -224,12 +235,9 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
if err := m.Unpack(p); err != nil { if err := m.Unpack(p); err != nil {
return nil, err return nil, err
} }
if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil { if ts, tp := m.IsTsig(), t.tsigProvider(); ts != nil && tp != nil {
if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
return m, ErrSecret
}
// Need to work on the original message p, as that was used to calculate the tsig. // Need to work on the original message p, as that was used to calculate the tsig.
err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly) err = TsigVerifyWithProvider(p, tp, t.tsigRequestMAC, t.tsigTimersOnly)
t.tsigRequestMAC = ts.MAC t.tsigRequestMAC = ts.MAC
} }
return m, err return m, err
@ -238,11 +246,8 @@ func (t *Transfer) ReadMsg() (*Msg, error) {
// WriteMsg writes a message through the transfer connection t. // WriteMsg writes a message through the transfer connection t.
func (t *Transfer) WriteMsg(m *Msg) (err error) { func (t *Transfer) WriteMsg(m *Msg) (err error) {
var out []byte var out []byte
if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil { if ts, tp := m.IsTsig(), t.tsigProvider(); ts != nil && tp != nil {
if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok { out, t.tsigRequestMAC, err = TsigGenerateWithProvider(m, tp, t.tsigRequestMAC, t.tsigTimersOnly)
return ErrSecret
}
out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
} else { } else {
out, err = m.Pack() out, err = m.Pack()
} }

View File

@ -51,7 +51,7 @@ type Counter interface {
// will lead to a valid (label-less) exemplar. But if Labels is nil, the current // will lead to a valid (label-less) exemplar. But if Labels is nil, the current
// exemplar is left in place. AddWithExemplar panics if the value is < 0, if any // exemplar is left in place. AddWithExemplar panics if the value is < 0, if any
// of the provided labels are invalid, or if the provided labels contain more // of the provided labels are invalid, or if the provided labels contain more
// than 64 runes in total. // than 128 runes in total.
type ExemplarAdder interface { type ExemplarAdder interface {
AddWithExemplar(value float64, exemplar Labels) AddWithExemplar(value float64, exemplar Labels)
} }

View File

@ -20,6 +20,9 @@ import (
"strings" "strings"
"github.com/cespare/xxhash/v2" "github.com/cespare/xxhash/v2"
"github.com/prometheus/client_golang/prometheus/internal"
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
@ -154,7 +157,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
Value: proto.String(v), Value: proto.String(v),
}) })
} }
sort.Sort(labelPairSorter(d.constLabelPairs)) sort.Sort(internal.LabelPairSorter(d.constLabelPairs))
return d return d
} }

View File

@ -0,0 +1,26 @@
// Copyright 2015 The Prometheus 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.
//go:build !js || wasm
// +build !js wasm
package prometheus
import "os"
func getPIDFn() func() (int, error) {
pid := os.Getpid()
return func() (int, error) {
return pid, nil
}
}

View File

@ -0,0 +1,23 @@
// Copyright 2015 The Prometheus 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.
//go:build js && !wasm
// +build js,!wasm
package prometheus
func getPIDFn() func() (int, error) {
return func() (int, error) {
return 1, nil
}
}

View File

@ -19,6 +19,10 @@ import (
"time" "time"
) )
// goRuntimeMemStats provides the metrics initially provided by runtime.ReadMemStats.
// From Go 1.17 those similar (and better) statistics are provided by runtime/metrics, so
// while eval closure works on runtime.MemStats, the struct from Go 1.17+ is
// populated using runtime/metrics.
func goRuntimeMemStats() memStatsMetrics { func goRuntimeMemStats() memStatsMetrics {
return memStatsMetrics{ return memStatsMetrics{
{ {
@ -197,14 +201,6 @@ func goRuntimeMemStats() memStatsMetrics {
), ),
eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) }, eval: func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
valType: GaugeValue, valType: GaugeValue,
}, {
desc: NewDesc(
memstatNamespace("gc_cpu_fraction"),
"The fraction of this program's available CPU time used by the GC since the program started.",
nil, nil,
),
eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
valType: GaugeValue,
}, },
} }
} }
@ -232,7 +228,7 @@ func newBaseGoCollector() baseGoCollector {
"A summary of the pause duration of garbage collection cycles.", "A summary of the pause duration of garbage collection cycles.",
nil, nil), nil, nil),
gcLastTimeDesc: NewDesc( gcLastTimeDesc: NewDesc(
memstatNamespace("last_gc_time_seconds"), "go_memstats_last_gc_time_seconds",
"Number of seconds since 1970 of last garbage collection.", "Number of seconds since 1970 of last garbage collection.",
nil, nil), nil, nil),
goInfoDesc: NewDesc( goInfoDesc: NewDesc(
@ -254,8 +250,9 @@ func (c *baseGoCollector) Describe(ch chan<- *Desc) {
// Collect returns the current state of all metrics of the collector. // Collect returns the current state of all metrics of the collector.
func (c *baseGoCollector) Collect(ch chan<- Metric) { func (c *baseGoCollector) Collect(ch chan<- Metric) {
ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine())) ch <- MustNewConstMetric(c.goroutinesDesc, GaugeValue, float64(runtime.NumGoroutine()))
n, _ := runtime.ThreadCreateProfile(nil)
ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, float64(n)) n := getRuntimeNumThreads()
ch <- MustNewConstMetric(c.threadsDesc, GaugeValue, n)
var stats debug.GCStats var stats debug.GCStats
stats.PauseQuantiles = make([]time.Duration, 5) stats.PauseQuantiles = make([]time.Duration, 5)
@ -268,7 +265,6 @@ func (c *baseGoCollector) Collect(ch chan<- Metric) {
quantiles[0.0] = stats.PauseQuantiles[0].Seconds() quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles) ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), stats.PauseTotal.Seconds(), quantiles)
ch <- MustNewConstMetric(c.gcLastTimeDesc, GaugeValue, float64(stats.LastGC.UnixNano())/1e9) ch <- MustNewConstMetric(c.gcLastTimeDesc, GaugeValue, float64(stats.LastGC.UnixNano())/1e9)
ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1) ch <- MustNewConstMetric(c.goInfoDesc, GaugeValue, 1)
} }

View File

@ -40,13 +40,28 @@ type goCollector struct {
// //
// Deprecated: Use collectors.NewGoCollector instead. // Deprecated: Use collectors.NewGoCollector instead.
func NewGoCollector() Collector { func NewGoCollector() Collector {
msMetrics := goRuntimeMemStats()
msMetrics = append(msMetrics, struct {
desc *Desc
eval func(*runtime.MemStats) float64
valType ValueType
}{
// This metric is omitted in Go1.17+, see https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
desc: NewDesc(
memstatNamespace("gc_cpu_fraction"),
"The fraction of this program's available CPU time used by the GC since the program started.",
nil, nil,
),
eval: func(ms *runtime.MemStats) float64 { return ms.GCCPUFraction },
valType: GaugeValue,
})
return &goCollector{ return &goCollector{
base: newBaseGoCollector(), base: newBaseGoCollector(),
msLast: &runtime.MemStats{}, msLast: &runtime.MemStats{},
msRead: runtime.ReadMemStats, msRead: runtime.ReadMemStats,
msMaxWait: time.Second, msMaxWait: time.Second,
msMaxAge: 5 * time.Minute, msMaxAge: 5 * time.Minute,
msMetrics: goRuntimeMemStats(), msMetrics: msMetrics,
} }
} }

View File

@ -25,10 +25,72 @@ import (
//nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility. //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/prometheus/client_golang/prometheus/internal"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
"github.com/prometheus/client_golang/prometheus/internal"
) )
const (
// constants for strings referenced more than once.
goGCHeapTinyAllocsObjects = "/gc/heap/tiny/allocs:objects"
goGCHeapAllocsObjects = "/gc/heap/allocs:objects"
goGCHeapFreesObjects = "/gc/heap/frees:objects"
goGCHeapFreesBytes = "/gc/heap/frees:bytes"
goGCHeapAllocsBytes = "/gc/heap/allocs:bytes"
goGCHeapObjects = "/gc/heap/objects:objects"
goGCHeapGoalBytes = "/gc/heap/goal:bytes"
goMemoryClassesTotalBytes = "/memory/classes/total:bytes"
goMemoryClassesHeapObjectsBytes = "/memory/classes/heap/objects:bytes"
goMemoryClassesHeapUnusedBytes = "/memory/classes/heap/unused:bytes"
goMemoryClassesHeapReleasedBytes = "/memory/classes/heap/released:bytes"
goMemoryClassesHeapFreeBytes = "/memory/classes/heap/free:bytes"
goMemoryClassesHeapStacksBytes = "/memory/classes/heap/stacks:bytes"
goMemoryClassesOSStacksBytes = "/memory/classes/os-stacks:bytes"
goMemoryClassesMetadataMSpanInuseBytes = "/memory/classes/metadata/mspan/inuse:bytes"
goMemoryClassesMetadataMSPanFreeBytes = "/memory/classes/metadata/mspan/free:bytes"
goMemoryClassesMetadataMCacheInuseBytes = "/memory/classes/metadata/mcache/inuse:bytes"
goMemoryClassesMetadataMCacheFreeBytes = "/memory/classes/metadata/mcache/free:bytes"
goMemoryClassesProfilingBucketsBytes = "/memory/classes/profiling/buckets:bytes"
goMemoryClassesMetadataOtherBytes = "/memory/classes/metadata/other:bytes"
goMemoryClassesOtherBytes = "/memory/classes/other:bytes"
)
// rmNamesForMemStatsMetrics represents runtime/metrics names required to populate goRuntimeMemStats from like logic.
var rmNamesForMemStatsMetrics = []string{
goGCHeapTinyAllocsObjects,
goGCHeapAllocsObjects,
goGCHeapFreesObjects,
goGCHeapAllocsBytes,
goGCHeapObjects,
goGCHeapGoalBytes,
goMemoryClassesTotalBytes,
goMemoryClassesHeapObjectsBytes,
goMemoryClassesHeapUnusedBytes,
goMemoryClassesHeapReleasedBytes,
goMemoryClassesHeapFreeBytes,
goMemoryClassesHeapStacksBytes,
goMemoryClassesOSStacksBytes,
goMemoryClassesMetadataMSpanInuseBytes,
goMemoryClassesMetadataMSPanFreeBytes,
goMemoryClassesMetadataMCacheInuseBytes,
goMemoryClassesMetadataMCacheFreeBytes,
goMemoryClassesProfilingBucketsBytes,
goMemoryClassesMetadataOtherBytes,
goMemoryClassesOtherBytes,
}
func bestEffortLookupRM(lookup []string) []metrics.Description {
ret := make([]metrics.Description, 0, len(lookup))
for _, rm := range metrics.All() {
for _, m := range lookup {
if m == rm.Name {
ret = append(ret, rm)
}
}
}
return ret
}
type goCollector struct { type goCollector struct {
base baseGoCollector base baseGoCollector
@ -36,70 +98,124 @@ type goCollector struct {
// snapshot is always produced by Collect. // snapshot is always produced by Collect.
mu sync.Mutex mu sync.Mutex
// rm... fields all pertain to the runtime/metrics package. // Contains all samples that has to retrieved from runtime/metrics (not all of them will be exposed).
rmSampleBuf []metrics.Sample sampleBuf []metrics.Sample
rmSampleMap map[string]*metrics.Sample // sampleMap allows lookup for MemStats metrics and runtime/metrics histograms for exact sums.
rmMetrics []collectorMetric sampleMap map[string]*metrics.Sample
// rmExposedMetrics represents all runtime/metrics package metrics
// that were configured to be exposed.
rmExposedMetrics []collectorMetric
rmExactSumMapForHist map[string]string
// With Go 1.17, the runtime/metrics package was introduced. // With Go 1.17, the runtime/metrics package was introduced.
// From that point on, metric names produced by the runtime/metrics // From that point on, metric names produced by the runtime/metrics
// package could be generated from runtime/metrics names. However, // package could be generated from runtime/metrics names. However,
// these differ from the old names for the same values. // these differ from the old names for the same values.
// //
// This field exist to export the same values under the old names // This field exists to export the same values under the old names
// as well. // as well.
msMetrics memStatsMetrics msMetrics memStatsMetrics
msMetricsEnabled bool
}
type rmMetricDesc struct {
metrics.Description
}
func matchRuntimeMetricsRules(rules []internal.GoCollectorRule) []rmMetricDesc {
var descs []rmMetricDesc
for _, d := range metrics.All() {
var (
deny = true
desc rmMetricDesc
)
for _, r := range rules {
if !r.Matcher.MatchString(d.Name) {
continue
}
deny = r.Deny
}
if deny {
continue
}
desc.Description = d
descs = append(descs, desc)
}
return descs
}
func defaultGoCollectorOptions() internal.GoCollectorOptions {
return internal.GoCollectorOptions{
RuntimeMetricSumForHist: map[string]string{
"/gc/heap/allocs-by-size:bytes": goGCHeapAllocsBytes,
"/gc/heap/frees-by-size:bytes": goGCHeapFreesBytes,
},
RuntimeMetricRules: []internal.GoCollectorRule{
//{Matcher: regexp.MustCompile("")},
},
}
} }
// NewGoCollector is the obsolete version of collectors.NewGoCollector. // NewGoCollector is the obsolete version of collectors.NewGoCollector.
// See there for documentation. // See there for documentation.
// //
// Deprecated: Use collectors.NewGoCollector instead. // Deprecated: Use collectors.NewGoCollector instead.
func NewGoCollector() Collector { func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
descriptions := metrics.All() opt := defaultGoCollectorOptions()
for _, o := range opts {
o(&opt)
}
exposedDescriptions := matchRuntimeMetricsRules(opt.RuntimeMetricRules)
// Collect all histogram samples so that we can get their buckets. // Collect all histogram samples so that we can get their buckets.
// The API guarantees that the buckets are always fixed for the lifetime // The API guarantees that the buckets are always fixed for the lifetime
// of the process. // of the process.
var histograms []metrics.Sample var histograms []metrics.Sample
for _, d := range descriptions { for _, d := range exposedDescriptions {
if d.Kind == metrics.KindFloat64Histogram { if d.Kind == metrics.KindFloat64Histogram {
histograms = append(histograms, metrics.Sample{Name: d.Name}) histograms = append(histograms, metrics.Sample{Name: d.Name})
} }
} }
if len(histograms) > 0 {
metrics.Read(histograms) metrics.Read(histograms)
}
bucketsMap := make(map[string][]float64) bucketsMap := make(map[string][]float64)
for i := range histograms { for i := range histograms {
bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets
} }
// Generate a Desc and ValueType for each runtime/metrics metric. // Generate a collector for each exposed runtime/metrics metric.
metricSet := make([]collectorMetric, 0, len(descriptions)) metricSet := make([]collectorMetric, 0, len(exposedDescriptions))
sampleBuf := make([]metrics.Sample, 0, len(descriptions)) // SampleBuf is used for reading from runtime/metrics.
sampleMap := make(map[string]*metrics.Sample, len(descriptions)) // We are assuming the largest case to have stable pointers for sampleMap purposes.
for i := range descriptions { sampleBuf := make([]metrics.Sample, 0, len(exposedDescriptions)+len(opt.RuntimeMetricSumForHist)+len(rmNamesForMemStatsMetrics))
d := &descriptions[i] sampleMap := make(map[string]*metrics.Sample, len(exposedDescriptions))
namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(d) for _, d := range exposedDescriptions {
namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(&d.Description)
if !ok { if !ok {
// Just ignore this metric; we can't do anything with it here. // Just ignore this metric; we can't do anything with it here.
// If a user decides to use the latest version of Go, we don't want // If a user decides to use the latest version of Go, we don't want
// to fail here. This condition is tested elsewhere. // to fail here. This condition is tested in TestExpectedRuntimeMetrics.
continue continue
} }
// Set up sample buffer for reading, and a map
// for quick lookup of sample values.
sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name}) sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1] sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]
var m collectorMetric var m collectorMetric
if d.Kind == metrics.KindFloat64Histogram { if d.Kind == metrics.KindFloat64Histogram {
_, hasSum := rmExactSumMap[d.Name] _, hasSum := opt.RuntimeMetricSumForHist[d.Name]
unit := d.Name[strings.IndexRune(d.Name, ':')+1:] unit := d.Name[strings.IndexRune(d.Name, ':')+1:]
m = newBatchHistogram( m = newBatchHistogram(
NewDesc( NewDesc(
BuildFQName(namespace, subsystem, name), BuildFQName(namespace, subsystem, name),
d.Description, d.Description.Description,
nil, nil,
nil, nil,
), ),
@ -111,24 +227,61 @@ func NewGoCollector() Collector {
Namespace: namespace, Namespace: namespace,
Subsystem: subsystem, Subsystem: subsystem,
Name: name, Name: name,
Help: d.Description, Help: d.Description.Description,
}) },
)
} else { } else {
m = NewGauge(GaugeOpts{ m = NewGauge(GaugeOpts{
Namespace: namespace, Namespace: namespace,
Subsystem: subsystem, Subsystem: subsystem,
Name: name, Name: name,
Help: d.Description, Help: d.Description.Description,
}) })
} }
metricSet = append(metricSet, m) metricSet = append(metricSet, m)
} }
// Add exact sum metrics to sampleBuf if not added before.
for _, h := range histograms {
sumMetric, ok := opt.RuntimeMetricSumForHist[h.Name]
if !ok {
continue
}
if _, ok := sampleMap[sumMetric]; ok {
continue
}
sampleBuf = append(sampleBuf, metrics.Sample{Name: sumMetric})
sampleMap[sumMetric] = &sampleBuf[len(sampleBuf)-1]
}
var (
msMetrics memStatsMetrics
msDescriptions []metrics.Description
)
if !opt.DisableMemStatsLikeMetrics {
msMetrics = goRuntimeMemStats()
msDescriptions = bestEffortLookupRM(rmNamesForMemStatsMetrics)
// Check if metric was not exposed before and if not, add to sampleBuf.
for _, mdDesc := range msDescriptions {
if _, ok := sampleMap[mdDesc.Name]; ok {
continue
}
sampleBuf = append(sampleBuf, metrics.Sample{Name: mdDesc.Name})
sampleMap[mdDesc.Name] = &sampleBuf[len(sampleBuf)-1]
}
}
return &goCollector{ return &goCollector{
base: newBaseGoCollector(), base: newBaseGoCollector(),
rmSampleBuf: sampleBuf, sampleBuf: sampleBuf,
rmSampleMap: sampleMap, sampleMap: sampleMap,
rmMetrics: metricSet, rmExposedMetrics: metricSet,
msMetrics: goRuntimeMemStats(), rmExactSumMapForHist: opt.RuntimeMetricSumForHist,
msMetrics: msMetrics,
msMetricsEnabled: !opt.DisableMemStatsLikeMetrics,
} }
} }
@ -138,7 +291,7 @@ func (c *goCollector) Describe(ch chan<- *Desc) {
for _, i := range c.msMetrics { for _, i := range c.msMetrics {
ch <- i.desc ch <- i.desc
} }
for _, m := range c.rmMetrics { for _, m := range c.rmExposedMetrics {
ch <- m.Desc() ch <- m.Desc()
} }
} }
@ -148,8 +301,12 @@ func (c *goCollector) Collect(ch chan<- Metric) {
// Collect base non-memory metrics. // Collect base non-memory metrics.
c.base.Collect(ch) c.base.Collect(ch)
if len(c.sampleBuf) == 0 {
return
}
// Collect must be thread-safe, so prevent concurrent use of // Collect must be thread-safe, so prevent concurrent use of
// rmSampleBuf. Just read into rmSampleBuf but write all the data // sampleBuf elements. Just read into sampleBuf but write all the data
// we get into our Metrics or MemStats. // we get into our Metrics or MemStats.
// //
// This lock also ensures that the Metrics we send out are all from // This lock also ensures that the Metrics we send out are all from
@ -164,14 +321,17 @@ func (c *goCollector) Collect(ch chan<- Metric) {
defer c.mu.Unlock() defer c.mu.Unlock()
// Populate runtime/metrics sample buffer. // Populate runtime/metrics sample buffer.
metrics.Read(c.rmSampleBuf) metrics.Read(c.sampleBuf)
// Collect all our runtime/metrics user chose to expose from sampleBuf (if any).
for i, metric := range c.rmExposedMetrics {
// We created samples for exposed metrics first in order, so indexes match.
sample := c.sampleBuf[i]
// Update all our metrics from rmSampleBuf.
for i, sample := range c.rmSampleBuf {
// N.B. switch on concrete type because it's significantly more efficient // N.B. switch on concrete type because it's significantly more efficient
// than checking for the Counter and Gauge interface implementations. In // than checking for the Counter and Gauge interface implementations. In
// this case, we control all the types here. // this case, we control all the types here.
switch m := c.rmMetrics[i].(type) { switch m := metric.(type) {
case *counter: case *counter:
// Guard against decreases. This should never happen, but a failure // Guard against decreases. This should never happen, but a failure
// to do so will result in a panic, which is a harsh consequence for // to do so will result in a panic, which is a harsh consequence for
@ -191,14 +351,17 @@ func (c *goCollector) Collect(ch chan<- Metric) {
panic("unexpected metric type") panic("unexpected metric type")
} }
} }
if c.msMetricsEnabled {
// ms is a dummy MemStats that we populate ourselves so that we can // ms is a dummy MemStats that we populate ourselves so that we can
// populate the old metrics from it. // populate the old metrics from it if goMemStatsCollection is enabled.
var ms runtime.MemStats var ms runtime.MemStats
memStatsFromRM(&ms, c.rmSampleMap) memStatsFromRM(&ms, c.sampleMap)
for _, i := range c.msMetrics { for _, i := range c.msMetrics {
ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms)) ch <- MustNewConstMetric(i.desc, i.valType, i.eval(&ms))
} }
} }
}
// unwrapScalarRMValue unwraps a runtime/metrics value that is assumed // unwrapScalarRMValue unwraps a runtime/metrics value that is assumed
// to be scalar and returns the equivalent float64 value. Panics if the // to be scalar and returns the equivalent float64 value. Panics if the
@ -224,11 +387,6 @@ func unwrapScalarRMValue(v metrics.Value) float64 {
} }
} }
var rmExactSumMap = map[string]string{
"/gc/heap/allocs-by-size:bytes": "/gc/heap/allocs:bytes",
"/gc/heap/frees-by-size:bytes": "/gc/heap/frees:bytes",
}
// exactSumFor takes a runtime/metrics metric name (that is assumed to // exactSumFor takes a runtime/metrics metric name (that is assumed to
// be of kind KindFloat64Histogram) and returns its exact sum and whether // be of kind KindFloat64Histogram) and returns its exact sum and whether
// its exact sum exists. // its exact sum exists.
@ -236,11 +394,11 @@ var rmExactSumMap = map[string]string{
// The runtime/metrics API for histograms doesn't currently expose exact // The runtime/metrics API for histograms doesn't currently expose exact
// sums, but some of the other metrics are in fact exact sums of histograms. // sums, but some of the other metrics are in fact exact sums of histograms.
func (c *goCollector) exactSumFor(rmName string) float64 { func (c *goCollector) exactSumFor(rmName string) float64 {
sumName, ok := rmExactSumMap[rmName] sumName, ok := c.rmExactSumMapForHist[rmName]
if !ok { if !ok {
return 0 return 0
} }
s, ok := c.rmSampleMap[sumName] s, ok := c.sampleMap[sumName]
if !ok { if !ok {
return 0 return 0
} }
@ -261,35 +419,30 @@ func memStatsFromRM(ms *runtime.MemStats, rm map[string]*metrics.Sample) {
// while having Mallocs - Frees still represent a live object count. // while having Mallocs - Frees still represent a live object count.
// Unfortunately, MemStats doesn't actually export a large allocation count, // Unfortunately, MemStats doesn't actually export a large allocation count,
// so it's impossible to pull this number out directly. // so it's impossible to pull this number out directly.
tinyAllocs := lookupOrZero("/gc/heap/tiny/allocs:objects") tinyAllocs := lookupOrZero(goGCHeapTinyAllocsObjects)
ms.Mallocs = lookupOrZero("/gc/heap/allocs:objects") + tinyAllocs ms.Mallocs = lookupOrZero(goGCHeapAllocsObjects) + tinyAllocs
ms.Frees = lookupOrZero("/gc/heap/frees:objects") + tinyAllocs ms.Frees = lookupOrZero(goGCHeapFreesObjects) + tinyAllocs
ms.TotalAlloc = lookupOrZero("/gc/heap/allocs:bytes") ms.TotalAlloc = lookupOrZero(goGCHeapAllocsBytes)
ms.Sys = lookupOrZero("/memory/classes/total:bytes") ms.Sys = lookupOrZero(goMemoryClassesTotalBytes)
ms.Lookups = 0 // Already always zero. ms.Lookups = 0 // Already always zero.
ms.HeapAlloc = lookupOrZero("/memory/classes/heap/objects:bytes") ms.HeapAlloc = lookupOrZero(goMemoryClassesHeapObjectsBytes)
ms.Alloc = ms.HeapAlloc ms.Alloc = ms.HeapAlloc
ms.HeapInuse = ms.HeapAlloc + lookupOrZero("/memory/classes/heap/unused:bytes") ms.HeapInuse = ms.HeapAlloc + lookupOrZero(goMemoryClassesHeapUnusedBytes)
ms.HeapReleased = lookupOrZero("/memory/classes/heap/released:bytes") ms.HeapReleased = lookupOrZero(goMemoryClassesHeapReleasedBytes)
ms.HeapIdle = ms.HeapReleased + lookupOrZero("/memory/classes/heap/free:bytes") ms.HeapIdle = ms.HeapReleased + lookupOrZero(goMemoryClassesHeapFreeBytes)
ms.HeapSys = ms.HeapInuse + ms.HeapIdle ms.HeapSys = ms.HeapInuse + ms.HeapIdle
ms.HeapObjects = lookupOrZero("/gc/heap/objects:objects") ms.HeapObjects = lookupOrZero(goGCHeapObjects)
ms.StackInuse = lookupOrZero("/memory/classes/heap/stacks:bytes") ms.StackInuse = lookupOrZero(goMemoryClassesHeapStacksBytes)
ms.StackSys = ms.StackInuse + lookupOrZero("/memory/classes/os-stacks:bytes") ms.StackSys = ms.StackInuse + lookupOrZero(goMemoryClassesOSStacksBytes)
ms.MSpanInuse = lookupOrZero("/memory/classes/metadata/mspan/inuse:bytes") ms.MSpanInuse = lookupOrZero(goMemoryClassesMetadataMSpanInuseBytes)
ms.MSpanSys = ms.MSpanInuse + lookupOrZero("/memory/classes/metadata/mspan/free:bytes") ms.MSpanSys = ms.MSpanInuse + lookupOrZero(goMemoryClassesMetadataMSPanFreeBytes)
ms.MCacheInuse = lookupOrZero("/memory/classes/metadata/mcache/inuse:bytes") ms.MCacheInuse = lookupOrZero(goMemoryClassesMetadataMCacheInuseBytes)
ms.MCacheSys = ms.MCacheInuse + lookupOrZero("/memory/classes/metadata/mcache/free:bytes") ms.MCacheSys = ms.MCacheInuse + lookupOrZero(goMemoryClassesMetadataMCacheFreeBytes)
ms.BuckHashSys = lookupOrZero("/memory/classes/profiling/buckets:bytes") ms.BuckHashSys = lookupOrZero(goMemoryClassesProfilingBucketsBytes)
ms.GCSys = lookupOrZero("/memory/classes/metadata/other:bytes") ms.GCSys = lookupOrZero(goMemoryClassesMetadataOtherBytes)
ms.OtherSys = lookupOrZero("/memory/classes/other:bytes") ms.OtherSys = lookupOrZero(goMemoryClassesOtherBytes)
ms.NextGC = lookupOrZero("/gc/heap/goal:bytes") ms.NextGC = lookupOrZero(goGCHeapGoalBytes)
// N.B. LastGC is omitted because runtime.GCStats already has this.
// See https://github.com/prometheus/client_golang/issues/842#issuecomment-861812034
// for more details.
ms.LastGC = 0
// N.B. GCCPUFraction is intentionally omitted. This metric is not useful, // N.B. GCCPUFraction is intentionally omitted. This metric is not useful,
// and often misleading due to the fact that it's an average over the lifetime // and often misleading due to the fact that it's an average over the lifetime
@ -324,6 +477,11 @@ type batchHistogram struct {
// buckets must always be from the runtime/metrics package, following // buckets must always be from the runtime/metrics package, following
// the same conventions. // the same conventions.
func newBatchHistogram(desc *Desc, buckets []float64, hasSum bool) *batchHistogram { func newBatchHistogram(desc *Desc, buckets []float64, hasSum bool) *batchHistogram {
// We need to remove -Inf values. runtime/metrics keeps them around.
// But -Inf bucket should not be allowed for prometheus histograms.
if buckets[0] == math.Inf(-1) {
buckets = buckets[1:]
}
h := &batchHistogram{ h := &batchHistogram{
desc: desc, desc: desc,
buckets: buckets, buckets: buckets,
@ -382,9 +540,11 @@ func (h *batchHistogram) Write(out *dto.Metric) error {
for i, count := range h.counts { for i, count := range h.counts {
totalCount += count totalCount += count
if !h.hasSum { if !h.hasSum {
if count != 0 {
// N.B. This computed sum is an underestimate. // N.B. This computed sum is an underestimate.
sum += h.buckets[i] * float64(count) sum += h.buckets[i] * float64(count)
} }
}
// Skip the +Inf bucket, but only for the bucket list. // Skip the +Inf bucket, but only for the bucket list.
// It must still count for sum and totalCount. // It must still count for sum and totalCount.

View File

@ -581,11 +581,11 @@ func (h *constHistogram) Desc() *Desc {
func (h *constHistogram) Write(out *dto.Metric) error { func (h *constHistogram) Write(out *dto.Metric) error {
his := &dto.Histogram{} his := &dto.Histogram{}
buckets := make([]*dto.Bucket, 0, len(h.buckets)) buckets := make([]*dto.Bucket, 0, len(h.buckets))
his.SampleCount = proto.Uint64(h.count) his.SampleCount = proto.Uint64(h.count)
his.SampleSum = proto.Float64(h.sum) his.SampleSum = proto.Float64(h.sum)
for upperBound, count := range h.buckets { for upperBound, count := range h.buckets {
buckets = append(buckets, &dto.Bucket{ buckets = append(buckets, &dto.Bucket{
CumulativeCount: proto.Uint64(count), CumulativeCount: proto.Uint64(count),

View File

@ -0,0 +1,651 @@
// Copyright 2022 The Prometheus 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.
//
// It provides tools to compare sequences of strings and generate textual diffs.
//
// Maintaining `GetUnifiedDiffString` here because original repository
// (https://github.com/pmezard/go-difflib) is no loger maintained.
package internal
import (
"bufio"
"bytes"
"fmt"
"io"
"strings"
)
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func calculateRatio(matches, length int) float64 {
if length > 0 {
return 2.0 * float64(matches) / float64(length)
}
return 1.0
}
type Match struct {
A int
B int
Size int
}
type OpCode struct {
Tag byte
I1 int
I2 int
J1 int
J2 int
}
// SequenceMatcher compares sequence of strings. The basic
// algorithm predates, and is a little fancier than, an algorithm
// published in the late 1980's by Ratcliff and Obershelp under the
// hyperbolic name "gestalt pattern matching". The basic idea is to find
// the longest contiguous matching subsequence that contains no "junk"
// elements (R-O doesn't address junk). The same idea is then applied
// recursively to the pieces of the sequences to the left and to the right
// of the matching subsequence. This does not yield minimal edit
// sequences, but does tend to yield matches that "look right" to people.
//
// SequenceMatcher tries to compute a "human-friendly diff" between two
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
// longest *contiguous* & junk-free matching subsequence. That's what
// catches peoples' eyes. The Windows(tm) windiff has another interesting
// notion, pairing up elements that appear uniquely in each sequence.
// That, and the method here, appear to yield more intuitive difference
// reports than does diff. This method appears to be the least vulnerable
// to synching up on blocks of "junk lines", though (like blank lines in
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
// because this is the only method of the 3 that has a *concept* of
// "junk" <wink>.
//
// Timing: Basic R-O is cubic time worst case and quadratic time expected
// case. SequenceMatcher is quadratic time for the worst case and has
// expected-case behavior dependent in a complicated way on how many
// elements the sequences have in common; best case time is linear.
type SequenceMatcher struct {
a []string
b []string
b2j map[string][]int
IsJunk func(string) bool
autoJunk bool
bJunk map[string]struct{}
matchingBlocks []Match
fullBCount map[string]int
bPopular map[string]struct{}
opCodes []OpCode
}
func NewMatcher(a, b []string) *SequenceMatcher {
m := SequenceMatcher{autoJunk: true}
m.SetSeqs(a, b)
return &m
}
func NewMatcherWithJunk(a, b []string, autoJunk bool,
isJunk func(string) bool,
) *SequenceMatcher {
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
m.SetSeqs(a, b)
return &m
}
// Set two sequences to be compared.
func (m *SequenceMatcher) SetSeqs(a, b []string) {
m.SetSeq1(a)
m.SetSeq2(b)
}
// Set the first sequence to be compared. The second sequence to be compared is
// not changed.
//
// SequenceMatcher computes and caches detailed information about the second
// sequence, so if you want to compare one sequence S against many sequences,
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
// sequences.
//
// See also SetSeqs() and SetSeq2().
func (m *SequenceMatcher) SetSeq1(a []string) {
if &a == &m.a {
return
}
m.a = a
m.matchingBlocks = nil
m.opCodes = nil
}
// Set the second sequence to be compared. The first sequence to be compared is
// not changed.
func (m *SequenceMatcher) SetSeq2(b []string) {
if &b == &m.b {
return
}
m.b = b
m.matchingBlocks = nil
m.opCodes = nil
m.fullBCount = nil
m.chainB()
}
func (m *SequenceMatcher) chainB() {
// Populate line -> index mapping
b2j := map[string][]int{}
for i, s := range m.b {
indices := b2j[s]
indices = append(indices, i)
b2j[s] = indices
}
// Purge junk elements
m.bJunk = map[string]struct{}{}
if m.IsJunk != nil {
junk := m.bJunk
for s := range b2j {
if m.IsJunk(s) {
junk[s] = struct{}{}
}
}
for s := range junk {
delete(b2j, s)
}
}
// Purge remaining popular elements
popular := map[string]struct{}{}
n := len(m.b)
if m.autoJunk && n >= 200 {
ntest := n/100 + 1
for s, indices := range b2j {
if len(indices) > ntest {
popular[s] = struct{}{}
}
}
for s := range popular {
delete(b2j, s)
}
}
m.bPopular = popular
m.b2j = b2j
}
func (m *SequenceMatcher) isBJunk(s string) bool {
_, ok := m.bJunk[s]
return ok
}
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
//
// If IsJunk is not defined:
//
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
// alo <= i <= i+k <= ahi
// blo <= j <= j+k <= bhi
// and for all (i',j',k') meeting those conditions,
// k >= k'
// i <= i'
// and if i == i', j <= j'
//
// In other words, of all maximal matching blocks, return one that
// starts earliest in a, and of all those maximal matching blocks that
// start earliest in a, return the one that starts earliest in b.
//
// If IsJunk is defined, first the longest matching block is
// determined as above, but with the additional restriction that no
// junk element appears in the block. Then that block is extended as
// far as possible by matching (only) junk elements on both sides. So
// the resulting block never matches on junk except as identical junk
// happens to be adjacent to an "interesting" match.
//
// If no blocks match, return (alo, blo, 0).
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
// CAUTION: stripping common prefix or suffix would be incorrect.
// E.g.,
// ab
// acab
// Longest matching block is "ab", but if common prefix is
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
// strip, so ends up claiming that ab is changed to acab by
// inserting "ca" in the middle. That's minimal but unintuitive:
// "it's obvious" that someone inserted "ac" at the front.
// Windiff ends up at the same place as diff, but by pairing up
// the unique 'b's and then matching the first two 'a's.
besti, bestj, bestsize := alo, blo, 0
// find longest junk-free match
// during an iteration of the loop, j2len[j] = length of longest
// junk-free match ending with a[i-1] and b[j]
j2len := map[int]int{}
for i := alo; i != ahi; i++ {
// look at all instances of a[i] in b; note that because
// b2j has no junk keys, the loop is skipped if a[i] is junk
newj2len := map[int]int{}
for _, j := range m.b2j[m.a[i]] {
// a[i] matches b[j]
if j < blo {
continue
}
if j >= bhi {
break
}
k := j2len[j-1] + 1
newj2len[j] = k
if k > bestsize {
besti, bestj, bestsize = i-k+1, j-k+1, k
}
}
j2len = newj2len
}
// Extend the best by non-junk elements on each end. In particular,
// "popular" non-junk elements aren't in b2j, which greatly speeds
// the inner loop above, but also means "the best" match so far
// doesn't contain any junk *or* popular non-junk elements.
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
!m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize++
}
// Now that we have a wholly interesting match (albeit possibly
// empty!), we may as well suck up the matching junk on each
// side of it too. Can't think of a good reason not to, and it
// saves post-processing the (possibly considerable) expense of
// figuring out what to do with it. In the case of an empty
// interesting match, this is clearly the right thing to do,
// because no other kind of match is possible in the regions.
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize++
}
return Match{A: besti, B: bestj, Size: bestsize}
}
// Return list of triples describing matching subsequences.
//
// Each triple is of the form (i, j, n), and means that
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
// adjacent triples in the list, and the second is not the last triple in the
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
// adjacent equal blocks.
//
// The last triple is a dummy, (len(a), len(b), 0), and is the only
// triple with n==0.
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
if m.matchingBlocks != nil {
return m.matchingBlocks
}
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
match := m.findLongestMatch(alo, ahi, blo, bhi)
i, j, k := match.A, match.B, match.Size
if match.Size > 0 {
if alo < i && blo < j {
matched = matchBlocks(alo, i, blo, j, matched)
}
matched = append(matched, match)
if i+k < ahi && j+k < bhi {
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
}
}
return matched
}
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
// It's possible that we have adjacent equal blocks in the
// matching_blocks list now.
nonAdjacent := []Match{}
i1, j1, k1 := 0, 0, 0
for _, b := range matched {
// Is this block adjacent to i1, j1, k1?
i2, j2, k2 := b.A, b.B, b.Size
if i1+k1 == i2 && j1+k1 == j2 {
// Yes, so collapse them -- this just increases the length of
// the first block by the length of the second, and the first
// block so lengthened remains the block to compare against.
k1 += k2
} else {
// Not adjacent. Remember the first block (k1==0 means it's
// the dummy we started with), and make the second block the
// new block to compare against.
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
i1, j1, k1 = i2, j2, k2
}
}
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
m.matchingBlocks = nonAdjacent
return m.matchingBlocks
}
// Return list of 5-tuples describing how to turn a into b.
//
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
// tuple preceding it, and likewise for j1 == the previous j2.
//
// The tags are characters, with these meanings:
//
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
//
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
//
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
//
// 'e' (equal): a[i1:i2] == b[j1:j2]
func (m *SequenceMatcher) GetOpCodes() []OpCode {
if m.opCodes != nil {
return m.opCodes
}
i, j := 0, 0
matching := m.GetMatchingBlocks()
opCodes := make([]OpCode, 0, len(matching))
for _, m := range matching {
// invariant: we've pumped out correct diffs to change
// a[:i] into b[:j], and the next matching block is
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
// out a diff to change a[i:ai] into b[j:bj], pump out
// the matching block, and move (i,j) beyond the match
ai, bj, size := m.A, m.B, m.Size
tag := byte(0)
if i < ai && j < bj {
tag = 'r'
} else if i < ai {
tag = 'd'
} else if j < bj {
tag = 'i'
}
if tag > 0 {
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
}
i, j = ai+size, bj+size
// the list of matching blocks is terminated by a
// sentinel with size 0
if size > 0 {
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
}
}
m.opCodes = opCodes
return m.opCodes
}
// Isolate change clusters by eliminating ranges with no changes.
//
// Return a generator of groups with up to n lines of context.
// Each group is in the same format as returned by GetOpCodes().
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
if n < 0 {
n = 3
}
codes := m.GetOpCodes()
if len(codes) == 0 {
codes = []OpCode{{'e', 0, 1, 0, 1}}
}
// Fixup leading and trailing groups if they show no changes.
if codes[0].Tag == 'e' {
c := codes[0]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
}
if codes[len(codes)-1].Tag == 'e' {
c := codes[len(codes)-1]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
}
nn := n + n
groups := [][]OpCode{}
group := []OpCode{}
for _, c := range codes {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
// End the current group and start a new one whenever
// there is a large range with no changes.
if c.Tag == 'e' && i2-i1 > nn {
group = append(group, OpCode{
c.Tag, i1, min(i2, i1+n),
j1, min(j2, j1+n),
})
groups = append(groups, group)
group = []OpCode{}
i1, j1 = max(i1, i2-n), max(j1, j2-n)
}
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
}
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
groups = append(groups, group)
}
return groups
}
// Return a measure of the sequences' similarity (float in [0,1]).
//
// Where T is the total number of elements in both sequences, and
// M is the number of matches, this is 2.0*M / T.
// Note that this is 1 if the sequences are identical, and 0 if
// they have nothing in common.
//
// .Ratio() is expensive to compute if you haven't already computed
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
// want to try .QuickRatio() or .RealQuickRation() first to get an
// upper bound.
func (m *SequenceMatcher) Ratio() float64 {
matches := 0
for _, m := range m.GetMatchingBlocks() {
matches += m.Size
}
return calculateRatio(matches, len(m.a)+len(m.b))
}
// Return an upper bound on ratio() relatively quickly.
//
// This isn't defined beyond that it is an upper bound on .Ratio(), and
// is faster to compute.
func (m *SequenceMatcher) QuickRatio() float64 {
// viewing a and b as multisets, set matches to the cardinality
// of their intersection; this counts the number of matches
// without regard to order, so is clearly an upper bound
if m.fullBCount == nil {
m.fullBCount = map[string]int{}
for _, s := range m.b {
m.fullBCount[s]++
}
}
// avail[x] is the number of times x appears in 'b' less the
// number of times we've seen it in 'a' so far ... kinda
avail := map[string]int{}
matches := 0
for _, s := range m.a {
n, ok := avail[s]
if !ok {
n = m.fullBCount[s]
}
avail[s] = n - 1
if n > 0 {
matches++
}
}
return calculateRatio(matches, len(m.a)+len(m.b))
}
// Return an upper bound on ratio() very quickly.
//
// This isn't defined beyond that it is an upper bound on .Ratio(), and
// is faster to compute than either .Ratio() or .QuickRatio().
func (m *SequenceMatcher) RealQuickRatio() float64 {
la, lb := len(m.a), len(m.b)
return calculateRatio(min(la, lb), la+lb)
}
// Convert range to the "ed" format
func formatRangeUnified(start, stop int) string {
// Per the diff spec at http://www.unix.org/single_unix_specification/
beginning := start + 1 // lines start numbering with one
length := stop - start
if length == 1 {
return fmt.Sprintf("%d", beginning)
}
if length == 0 {
beginning-- // empty ranges begin at line just before the range
}
return fmt.Sprintf("%d,%d", beginning, length)
}
// Unified diff parameters
type UnifiedDiff struct {
A []string // First sequence lines
FromFile string // First file name
FromDate string // First file time
B []string // Second sequence lines
ToFile string // Second file name
ToDate string // Second file time
Eol string // Headers end of line, defaults to LF
Context int // Number of context lines
}
// Compare two sequences of lines; generate the delta as a unified diff.
//
// Unified diffs are a compact way of showing line changes and a few
// lines of context. The number of context lines is set by 'n' which
// defaults to three.
//
// By default, the diff control lines (those with ---, +++, or @@) are
// created with a trailing newline. This is helpful so that inputs
// created from file.readlines() result in diffs that are suitable for
// file.writelines() since both the inputs and outputs have trailing
// newlines.
//
// For inputs that do not have trailing newlines, set the lineterm
// argument to "" so that the output will be uniformly newline free.
//
// The unidiff format normally has a header for filenames and modification
// times. Any or all of these may be specified using strings for
// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
// The modification times are normally expressed in the ISO 8601 format.
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
buf := bufio.NewWriter(writer)
defer buf.Flush()
wf := func(format string, args ...interface{}) error {
_, err := buf.WriteString(fmt.Sprintf(format, args...))
return err
}
ws := func(s string) error {
_, err := buf.WriteString(s)
return err
}
if len(diff.Eol) == 0 {
diff.Eol = "\n"
}
started := false
m := NewMatcher(diff.A, diff.B)
for _, g := range m.GetGroupedOpCodes(diff.Context) {
if !started {
started = true
fromDate := ""
if len(diff.FromDate) > 0 {
fromDate = "\t" + diff.FromDate
}
toDate := ""
if len(diff.ToDate) > 0 {
toDate = "\t" + diff.ToDate
}
if diff.FromFile != "" || diff.ToFile != "" {
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
if err != nil {
return err
}
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
if err != nil {
return err
}
}
}
first, last := g[0], g[len(g)-1]
range1 := formatRangeUnified(first.I1, last.I2)
range2 := formatRangeUnified(first.J1, last.J2)
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
return err
}
for _, c := range g {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
if c.Tag == 'e' {
for _, line := range diff.A[i1:i2] {
if err := ws(" " + line); err != nil {
return err
}
}
continue
}
if c.Tag == 'r' || c.Tag == 'd' {
for _, line := range diff.A[i1:i2] {
if err := ws("-" + line); err != nil {
return err
}
}
}
if c.Tag == 'r' || c.Tag == 'i' {
for _, line := range diff.B[j1:j2] {
if err := ws("+" + line); err != nil {
return err
}
}
}
}
}
return nil
}
// Like WriteUnifiedDiff but returns the diff a string.
func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
w := &bytes.Buffer{}
err := WriteUnifiedDiff(w, diff)
return w.String(), err
}
// Split a string on "\n" while preserving them. The output can be used
// as input for UnifiedDiff and ContextDiff structures.
func SplitLines(s string) []string {
lines := strings.SplitAfter(s, "\n")
lines[len(lines)-1] += "\n"
return lines
}

View File

@ -0,0 +1,32 @@
// Copyright 2021 The Prometheus 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 internal
import "regexp"
type GoCollectorRule struct {
Matcher *regexp.Regexp
Deny bool
}
// GoCollectorOptions should not be used be directly by anything, except `collectors` package.
// Use it via collectors package instead. See issue
// https://github.com/prometheus/client_golang/issues/1030.
//
// This is internal, so external users only can use it via `collector.WithGoCollector*` methods
type GoCollectorOptions struct {
DisableMemStatsLikeMetrics bool
RuntimeMetricSumForHist map[string]string
RuntimeMetricRules []GoCollectorRule
}

View File

@ -61,9 +61,9 @@ func RuntimeMetricsToProm(d *metrics.Description) (string, string, string, bool)
// name has - replaced with _ and is concatenated with the unit and // name has - replaced with _ and is concatenated with the unit and
// other data. // other data.
name = strings.ReplaceAll(name, "-", "_") name = strings.ReplaceAll(name, "-", "_")
name = name + "_" + unit name += "_" + unit
if d.Cumulative { if d.Cumulative && d.Kind != metrics.KindFloat64Histogram {
name = name + "_total" name += "_total"
} }
valid := model.IsValidMetricName(model.LabelValue(namespace + "_" + subsystem + "_" + name)) valid := model.IsValidMetricName(model.LabelValue(namespace + "_" + subsystem + "_" + name))
@ -84,12 +84,12 @@ func RuntimeMetricsToProm(d *metrics.Description) (string, string, string, bool)
func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 { func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 {
switch unit { switch unit {
case "bytes": case "bytes":
// Rebucket as powers of 2. // Re-bucket as powers of 2.
return rebucketExp(buckets, 2) return reBucketExp(buckets, 2)
case "seconds": case "seconds":
// Rebucket as powers of 10 and then merge all buckets greater // Re-bucket as powers of 10 and then merge all buckets greater
// than 1 second into the +Inf bucket. // than 1 second into the +Inf bucket.
b := rebucketExp(buckets, 10) b := reBucketExp(buckets, 10)
for i := range b { for i := range b {
if b[i] <= 1 { if b[i] <= 1 {
continue continue
@ -103,11 +103,11 @@ func RuntimeMetricsBucketsForUnit(buckets []float64, unit string) []float64 {
return buckets return buckets
} }
// rebucketExp takes a list of bucket boundaries (lower bound inclusive) and // reBucketExp takes a list of bucket boundaries (lower bound inclusive) and
// downsamples the buckets to those a multiple of base apart. The end result // downsamples the buckets to those a multiple of base apart. The end result
// is a roughly exponential (in many cases, perfectly exponential) bucketing // is a roughly exponential (in many cases, perfectly exponential) bucketing
// scheme. // scheme.
func rebucketExp(buckets []float64, base float64) []float64 { func reBucketExp(buckets []float64, base float64) []float64 {
bucket := buckets[0] bucket := buckets[0]
var newBuckets []float64 var newBuckets []float64
// We may see a -Inf here, in which case, add it and skip it // We may see a -Inf here, in which case, add it and skip it

View File

@ -19,18 +19,34 @@ import (
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
) )
// metricSorter is a sortable slice of *dto.Metric. // LabelPairSorter implements sort.Interface. It is used to sort a slice of
type metricSorter []*dto.Metric // dto.LabelPair pointers.
type LabelPairSorter []*dto.LabelPair
func (s metricSorter) Len() int { func (s LabelPairSorter) Len() int {
return len(s) return len(s)
} }
func (s metricSorter) Swap(i, j int) { func (s LabelPairSorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i] s[i], s[j] = s[j], s[i]
} }
func (s metricSorter) Less(i, j int) bool { func (s LabelPairSorter) Less(i, j int) bool {
return s[i].GetName() < s[j].GetName()
}
// MetricSorter is a sortable slice of *dto.Metric.
type MetricSorter []*dto.Metric
func (s MetricSorter) Len() int {
return len(s)
}
func (s MetricSorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s MetricSorter) Less(i, j int) bool {
if len(s[i].Label) != len(s[j].Label) { if len(s[i].Label) != len(s[j].Label) {
// This should not happen. The metrics are // This should not happen. The metrics are
// inconsistent. However, we have to deal with the fact, as // inconsistent. However, we have to deal with the fact, as
@ -68,7 +84,7 @@ func (s metricSorter) Less(i, j int) bool {
// the slice, with the contained Metrics sorted within each MetricFamily. // the slice, with the contained Metrics sorted within each MetricFamily.
func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily { func NormalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
for _, mf := range metricFamiliesByName { for _, mf := range metricFamiliesByName {
sort.Sort(metricSorter(mf.Metric)) sort.Sort(MetricSorter(mf.Metric))
} }
names := make([]string, 0, len(metricFamiliesByName)) names := make([]string, 0, len(metricFamiliesByName))
for name, mf := range metricFamiliesByName { for name, mf := range metricFamiliesByName {

View File

@ -39,7 +39,7 @@ var errInconsistentCardinality = errors.New("inconsistent label cardinality")
func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error {
return fmt.Errorf( return fmt.Errorf(
"%s: %q has %d variable labels named %q but %d values %q were provided", "%w: %q has %d variable labels named %q but %d values %q were provided",
errInconsistentCardinality, fqName, errInconsistentCardinality, fqName,
len(labels), labels, len(labels), labels,
len(labelValues), labelValues, len(labelValues), labelValues,
@ -49,7 +49,7 @@ func makeInconsistentCardinalityError(fqName string, labels, labelValues []strin
func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
if len(labels) != expectedNumberOfValues { if len(labels) != expectedNumberOfValues {
return fmt.Errorf( return fmt.Errorf(
"%s: expected %d label values but got %d in %#v", "%w: expected %d label values but got %d in %#v",
errInconsistentCardinality, expectedNumberOfValues, errInconsistentCardinality, expectedNumberOfValues,
len(labels), labels, len(labels), labels,
) )
@ -67,7 +67,7 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error {
func validateLabelValues(vals []string, expectedNumberOfValues int) error { func validateLabelValues(vals []string, expectedNumberOfValues int) error {
if len(vals) != expectedNumberOfValues { if len(vals) != expectedNumberOfValues {
return fmt.Errorf( return fmt.Errorf(
"%s: expected %d label values but got %d in %#v", "%w: expected %d label values but got %d in %#v",
errInconsistentCardinality, expectedNumberOfValues, errInconsistentCardinality, expectedNumberOfValues,
len(vals), vals, len(vals), vals,
) )

View File

@ -14,6 +14,9 @@
package prometheus package prometheus
import ( import (
"errors"
"math"
"sort"
"strings" "strings"
"time" "time"
@ -115,22 +118,6 @@ func BuildFQName(namespace, subsystem, name string) string {
return name return name
} }
// labelPairSorter implements sort.Interface. It is used to sort a slice of
// dto.LabelPair pointers.
type labelPairSorter []*dto.LabelPair
func (s labelPairSorter) Len() int {
return len(s)
}
func (s labelPairSorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s labelPairSorter) Less(i, j int) bool {
return s[i].GetName() < s[j].GetName()
}
type invalidMetric struct { type invalidMetric struct {
desc *Desc desc *Desc
err error err error
@ -174,3 +161,96 @@ func (m timestampedMetric) Write(pb *dto.Metric) error {
func NewMetricWithTimestamp(t time.Time, m Metric) Metric { func NewMetricWithTimestamp(t time.Time, m Metric) Metric {
return timestampedMetric{Metric: m, t: t} return timestampedMetric{Metric: m, t: t}
} }
type withExemplarsMetric struct {
Metric
exemplars []*dto.Exemplar
}
func (m *withExemplarsMetric) Write(pb *dto.Metric) error {
if err := m.Metric.Write(pb); err != nil {
return err
}
switch {
case pb.Counter != nil:
pb.Counter.Exemplar = m.exemplars[len(m.exemplars)-1]
case pb.Histogram != nil:
for _, e := range m.exemplars {
// pb.Histogram.Bucket are sorted by UpperBound.
i := sort.Search(len(pb.Histogram.Bucket), func(i int) bool {
return pb.Histogram.Bucket[i].GetUpperBound() >= e.GetValue()
})
if i < len(pb.Histogram.Bucket) {
pb.Histogram.Bucket[i].Exemplar = e
} else {
// The +Inf bucket should be explicitly added if there is an exemplar for it, similar to non-const histogram logic in https://github.com/prometheus/client_golang/blob/main/prometheus/histogram.go#L357-L365.
b := &dto.Bucket{
CumulativeCount: proto.Uint64(pb.Histogram.Bucket[len(pb.Histogram.GetBucket())-1].GetCumulativeCount()),
UpperBound: proto.Float64(math.Inf(1)),
Exemplar: e,
}
pb.Histogram.Bucket = append(pb.Histogram.Bucket, b)
}
}
default:
// TODO(bwplotka): Implement Gauge?
return errors.New("cannot inject exemplar into Gauge, Summary or Untyped")
}
return nil
}
// Exemplar is easier to use, user-facing representation of *dto.Exemplar.
type Exemplar struct {
Value float64
Labels Labels
// Optional.
// Default value (time.Time{}) indicates its empty, which should be
// understood as time.Now() time at the moment of creation of metric.
Timestamp time.Time
}
// NewMetricWithExemplars returns a new Metric wrapping the provided Metric with given
// exemplars. Exemplars are validated.
//
// Only last applicable exemplar is injected from the list.
// For example for Counter it means last exemplar is injected.
// For Histogram, it means last applicable exemplar for each bucket is injected.
//
// NewMetricWithExemplars works best with MustNewConstMetric and
// MustNewConstHistogram, see example.
func NewMetricWithExemplars(m Metric, exemplars ...Exemplar) (Metric, error) {
if len(exemplars) == 0 {
return nil, errors.New("no exemplar was passed for NewMetricWithExemplars")
}
var (
now = time.Now()
exs = make([]*dto.Exemplar, len(exemplars))
err error
)
for i, e := range exemplars {
ts := e.Timestamp
if ts == (time.Time{}) {
ts = now
}
exs[i], err = newExemplar(e.Value, ts, e.Labels)
if err != nil {
return nil, err
}
}
return &withExemplarsMetric{Metric: m, exemplars: exs}, nil
}
// MustNewMetricWithExemplars is a version of NewMetricWithExemplars that panics where
// NewMetricWithExemplars would have returned an error.
func MustNewMetricWithExemplars(m Metric, exemplars ...Exemplar) Metric {
ret, err := NewMetricWithExemplars(m, exemplars...)
if err != nil {
panic(err)
}
return ret
}

View File

@ -0,0 +1,25 @@
// Copyright 2018 The Prometheus 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.
//go:build !js || wasm
// +build !js wasm
package prometheus
import "runtime"
// getRuntimeNumThreads returns the number of open OS threads.
func getRuntimeNumThreads() float64 {
n, _ := runtime.ThreadCreateProfile(nil)
return float64(n)
}

View File

@ -0,0 +1,22 @@
// Copyright 2018 The Prometheus 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.
//go:build js && !wasm
// +build js,!wasm
package prometheus
// getRuntimeNumThreads returns the number of open OS threads.
func getRuntimeNumThreads() float64 {
return 1
}

View File

@ -58,7 +58,7 @@ type ObserverVec interface {
// current time as timestamp, and the provided Labels. Empty Labels will lead to // current time as timestamp, and the provided Labels. Empty Labels will lead to
// a valid (label-less) exemplar. But if Labels is nil, the current exemplar is // a valid (label-less) exemplar. But if Labels is nil, the current exemplar is
// left in place. ObserveWithExemplar panics if any of the provided labels are // left in place. ObserveWithExemplar panics if any of the provided labels are
// invalid or if the provided labels contain more than 64 runes in total. // invalid or if the provided labels contain more than 128 runes in total.
type ExemplarObserver interface { type ExemplarObserver interface {
ObserveWithExemplar(value float64, exemplar Labels) ObserveWithExemplar(value float64, exemplar Labels)
} }

View File

@ -16,7 +16,6 @@ package prometheus
import ( import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -104,8 +103,7 @@ func NewProcessCollector(opts ProcessCollectorOpts) Collector {
} }
if opts.PidFn == nil { if opts.PidFn == nil {
pid := os.Getpid() c.pidFn = getPIDFn()
c.pidFn = func() (int, error) { return pid, nil }
} else { } else {
c.pidFn = opts.PidFn c.pidFn = opts.PidFn
} }
@ -152,13 +150,13 @@ func (c *processCollector) reportError(ch chan<- Metric, desc *Desc, err error)
// It is meant to be used for the PidFn field in ProcessCollectorOpts. // It is meant to be used for the PidFn field in ProcessCollectorOpts.
func NewPidFileFn(pidFilePath string) func() (int, error) { func NewPidFileFn(pidFilePath string) func() (int, error) {
return func() (int, error) { return func() (int, error) {
content, err := ioutil.ReadFile(pidFilePath) content, err := os.ReadFile(pidFilePath)
if err != nil { if err != nil {
return 0, fmt.Errorf("can't read pid file %q: %+v", pidFilePath, err) return 0, fmt.Errorf("can't read pid file %q: %w", pidFilePath, err)
} }
pid, err := strconv.Atoi(strings.TrimSpace(string(content))) pid, err := strconv.Atoi(strings.TrimSpace(string(content)))
if err != nil { if err != nil {
return 0, fmt.Errorf("can't parse pid file %q: %+v", pidFilePath, err) return 0, fmt.Errorf("can't parse pid file %q: %w", pidFilePath, err)
} }
return pid, nil return pid, nil

View File

@ -0,0 +1,26 @@
// Copyright 2019 The Prometheus 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.
//go:build js
// +build js
package prometheus
func canCollectProcess() bool {
return false
}
func (c *processCollector) processCollect(ch chan<- Metric) {
// noop on this platform
return
}

View File

@ -11,8 +11,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !windows //go:build !windows && !js
// +build !windows // +build !windows,!js
package prometheus package prometheus

View File

@ -76,16 +76,19 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
return n, err return n, err
} }
type closeNotifierDelegator struct{ *responseWriterDelegator } type (
type flusherDelegator struct{ *responseWriterDelegator } closeNotifierDelegator struct{ *responseWriterDelegator }
type hijackerDelegator struct{ *responseWriterDelegator } flusherDelegator struct{ *responseWriterDelegator }
type readerFromDelegator struct{ *responseWriterDelegator } hijackerDelegator struct{ *responseWriterDelegator }
type pusherDelegator struct{ *responseWriterDelegator } readerFromDelegator struct{ *responseWriterDelegator }
pusherDelegator struct{ *responseWriterDelegator }
)
func (d closeNotifierDelegator) CloseNotify() <-chan bool { func (d closeNotifierDelegator) CloseNotify() <-chan bool {
//nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users. //nolint:staticcheck // Ignore SA1019. http.CloseNotifier is deprecated but we keep it here to not break existing users.
return d.ResponseWriter.(http.CloseNotifier).CloseNotify() return d.ResponseWriter.(http.CloseNotifier).CloseNotify()
} }
func (d flusherDelegator) Flush() { func (d flusherDelegator) Flush() {
// If applicable, call WriteHeader here so that observeWriteHeader is // If applicable, call WriteHeader here so that observeWriteHeader is
// handled appropriately. // handled appropriately.
@ -94,9 +97,11 @@ func (d flusherDelegator) Flush() {
} }
d.ResponseWriter.(http.Flusher).Flush() d.ResponseWriter.(http.Flusher).Flush()
} }
func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) { func (d hijackerDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return d.ResponseWriter.(http.Hijacker).Hijack() return d.ResponseWriter.(http.Hijacker).Hijack()
} }
func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) { func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
// If applicable, call WriteHeader here so that observeWriteHeader is // If applicable, call WriteHeader here so that observeWriteHeader is
// handled appropriately. // handled appropriately.
@ -107,6 +112,7 @@ func (d readerFromDelegator) ReadFrom(re io.Reader) (int64, error) {
d.written += n d.written += n
return n, err return n, err
} }
func (d pusherDelegator) Push(target string, opts *http.PushOptions) error { func (d pusherDelegator) Push(target string, opts *http.PushOptions) error {
return d.ResponseWriter.(http.Pusher).Push(target, opts) return d.ResponseWriter.(http.Pusher).Push(target, opts)
} }

View File

@ -33,6 +33,7 @@ package promhttp
import ( import (
"compress/gzip" "compress/gzip"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -84,6 +85,13 @@ func Handler() http.Handler {
// instrumentation. Use the InstrumentMetricHandler function to apply the same // instrumentation. Use the InstrumentMetricHandler function to apply the same
// kind of instrumentation as it is used by the Handler function. // kind of instrumentation as it is used by the Handler function.
func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
return HandlerForTransactional(prometheus.ToTransactionalGatherer(reg), opts)
}
// HandlerForTransactional is like HandlerFor, but it uses transactional gather, which
// can safely change in-place returned *dto.MetricFamily before call to `Gather` and after
// call to `done` of that `Gather`.
func HandlerForTransactional(reg prometheus.TransactionalGatherer, opts HandlerOpts) http.Handler {
var ( var (
inFlightSem chan struct{} inFlightSem chan struct{}
errCnt = prometheus.NewCounterVec( errCnt = prometheus.NewCounterVec(
@ -103,7 +111,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
errCnt.WithLabelValues("gathering") errCnt.WithLabelValues("gathering")
errCnt.WithLabelValues("encoding") errCnt.WithLabelValues("encoding")
if err := opts.Registry.Register(errCnt); err != nil { if err := opts.Registry.Register(errCnt); err != nil {
if are, ok := err.(prometheus.AlreadyRegisteredError); ok { are := &prometheus.AlreadyRegisteredError{}
if errors.As(err, are) {
errCnt = are.ExistingCollector.(*prometheus.CounterVec) errCnt = are.ExistingCollector.(*prometheus.CounterVec)
} else { } else {
panic(err) panic(err)
@ -123,7 +132,8 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
return return
} }
} }
mfs, err := reg.Gather() mfs, done, err := reg.Gather()
defer done()
if err != nil { if err != nil {
if opts.ErrorLog != nil { if opts.ErrorLog != nil {
opts.ErrorLog.Println("error gathering metrics:", err) opts.ErrorLog.Println("error gathering metrics:", err)
@ -242,7 +252,8 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht
cnt.WithLabelValues("500") cnt.WithLabelValues("500")
cnt.WithLabelValues("503") cnt.WithLabelValues("503")
if err := reg.Register(cnt); err != nil { if err := reg.Register(cnt); err != nil {
if are, ok := err.(prometheus.AlreadyRegisteredError); ok { are := &prometheus.AlreadyRegisteredError{}
if errors.As(err, are) {
cnt = are.ExistingCollector.(*prometheus.CounterVec) cnt = are.ExistingCollector.(*prometheus.CounterVec)
} else { } else {
panic(err) panic(err)
@ -254,7 +265,8 @@ func InstrumentMetricHandler(reg prometheus.Registerer, handler http.Handler) ht
Help: "Current number of scrapes being served.", Help: "Current number of scrapes being served.",
}) })
if err := reg.Register(gge); err != nil { if err := reg.Register(gge); err != nil {
if are, ok := err.(prometheus.AlreadyRegisteredError); ok { are := &prometheus.AlreadyRegisteredError{}
if errors.As(err, are) {
gge = are.ExistingCollector.(prometheus.Gauge) gge = are.ExistingCollector.(prometheus.Gauge)
} else { } else {
panic(err) panic(err)

View File

@ -38,11 +38,11 @@ func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
// //
// See the example for ExampleInstrumentRoundTripperDuration for example usage. // See the example for ExampleInstrumentRoundTripperDuration for example usage.
func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc { func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc {
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { return func(r *http.Request) (*http.Response, error) {
gauge.Inc() gauge.Inc()
defer gauge.Dec() defer gauge.Dec()
return next.RoundTrip(r) return next.RoundTrip(r)
}) }
} }
// InstrumentRoundTripperCounter is a middleware that wraps the provided // InstrumentRoundTripperCounter is a middleware that wraps the provided
@ -59,22 +59,29 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
// If the wrapped RoundTripper panics or returns a non-nil error, the Counter // If the wrapped RoundTripper panics or returns a non-nil error, the Counter
// is not incremented. // is not incremented.
// //
// Use with WithExemplarFromContext to instrument the exemplars on the counter of requests.
//
// See the example for ExampleInstrumentRoundTripperDuration for example usage. // See the example for ExampleInstrumentRoundTripperDuration for example usage.
func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc { func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
rtOpts := &option{} rtOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(rtOpts) o.apply(rtOpts)
} }
code, method := checkLabels(counter) code, method := checkLabels(counter)
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { return func(r *http.Request) (*http.Response, error) {
resp, err := next.RoundTrip(r) resp, err := next.RoundTrip(r)
if err == nil { if err == nil {
exemplarAdd(
counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)),
1,
rtOpts.getExemplarFn(r.Context()),
)
counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc() counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
} }
return resp, err return resp, err
}) }
} }
// InstrumentRoundTripperDuration is a middleware that wraps the provided // InstrumentRoundTripperDuration is a middleware that wraps the provided
@ -94,24 +101,30 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
// If the wrapped RoundTripper panics or returns a non-nil error, no values are // If the wrapped RoundTripper panics or returns a non-nil error, no values are
// reported. // reported.
// //
// Use with WithExemplarFromContext to instrument the exemplars on the duration histograms.
//
// Note that this method is only guaranteed to never observe negative durations // Note that this method is only guaranteed to never observe negative durations
// if used with Go1.9+. // if used with Go1.9+.
func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc { func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
rtOpts := &option{} rtOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(rtOpts) o.apply(rtOpts)
} }
code, method := checkLabels(obs) code, method := checkLabels(obs)
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { return func(r *http.Request) (*http.Response, error) {
start := time.Now() start := time.Now()
resp, err := next.RoundTrip(r) resp, err := next.RoundTrip(r)
if err == nil { if err == nil {
obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds()) exemplarObserve(
obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)),
time.Since(start).Seconds(),
rtOpts.getExemplarFn(r.Context()),
)
} }
return resp, err return resp, err
}) }
} }
// InstrumentTrace is used to offer flexibility in instrumenting the available // InstrumentTrace is used to offer flexibility in instrumenting the available
@ -149,7 +162,7 @@ type InstrumentTrace struct {
// //
// See the example for ExampleInstrumentRoundTripperDuration for example usage. // See the example for ExampleInstrumentRoundTripperDuration for example usage.
func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc { func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) RoundTripperFunc {
return RoundTripperFunc(func(r *http.Request) (*http.Response, error) { return func(r *http.Request) (*http.Response, error) {
start := time.Now() start := time.Now()
trace := &httptrace.ClientTrace{ trace := &httptrace.ClientTrace{
@ -231,5 +244,5 @@ func InstrumentRoundTripperTrace(it *InstrumentTrace, next http.RoundTripper) Ro
r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace)) r = r.WithContext(httptrace.WithClientTrace(r.Context(), trace))
return next.RoundTrip(r) return next.RoundTrip(r)
}) }
} }

View File

@ -28,6 +28,22 @@ import (
// magicString is used for the hacky label test in checkLabels. Remove once fixed. // magicString is used for the hacky label test in checkLabels. Remove once fixed.
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa" const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
func exemplarObserve(obs prometheus.Observer, val float64, labels map[string]string) {
if labels == nil {
obs.Observe(val)
return
}
obs.(prometheus.ExemplarObserver).ObserveWithExemplar(val, labels)
}
func exemplarAdd(obs prometheus.Counter, val float64, labels map[string]string) {
if labels == nil {
obs.Add(val)
return
}
obs.(prometheus.ExemplarAdder).AddWithExemplar(val, labels)
}
// InstrumentHandlerInFlight is a middleware that wraps the provided // InstrumentHandlerInFlight is a middleware that wraps the provided
// http.Handler. It sets the provided prometheus.Gauge to the number of // http.Handler. It sets the provided prometheus.Gauge to the number of
// requests currently handled by the wrapped http.Handler. // requests currently handled by the wrapped http.Handler.
@ -62,28 +78,37 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
// Note that this method is only guaranteed to never observe negative durations // Note that this method is only guaranteed to never observe negative durations
// if used with Go1.9+. // if used with Go1.9+.
func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc { func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
mwOpts := &option{} hOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(mwOpts) o.apply(hOpts)
} }
code, method := checkLabels(obs) code, method := checkLabels(obs)
if code { if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
now := time.Now() now := time.Now()
d := newDelegator(w, nil) d := newDelegator(w, nil)
next.ServeHTTP(d, r) next.ServeHTTP(d, r)
obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds()) exemplarObserve(
}) obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
time.Since(now).Seconds(),
hOpts.getExemplarFn(r.Context()),
)
}
} }
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
now := time.Now() now := time.Now()
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
}) exemplarObserve(
obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
time.Since(now).Seconds(),
hOpts.getExemplarFn(r.Context()),
)
}
} }
// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler // InstrumentHandlerCounter is a middleware that wraps the provided http.Handler
@ -104,25 +129,34 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, op
// //
// See the example for InstrumentHandlerDuration for example usage. // See the example for InstrumentHandlerDuration for example usage.
func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc { func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc {
mwOpts := &option{} hOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(mwOpts) o.apply(hOpts)
} }
code, method := checkLabels(counter) code, method := checkLabels(counter)
if code { if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
d := newDelegator(w, nil) d := newDelegator(w, nil)
next.ServeHTTP(d, r) next.ServeHTTP(d, r)
counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc()
}) exemplarAdd(
counter.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
1,
hOpts.getExemplarFn(r.Context()),
)
}
} }
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc() exemplarAdd(
}) counter.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
1,
hOpts.getExemplarFn(r.Context()),
)
}
} }
// InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided // InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
@ -148,20 +182,24 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler,
// //
// See the example for InstrumentHandlerDuration for example usage. // See the example for InstrumentHandlerDuration for example usage.
func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc { func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
mwOpts := &option{} hOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(mwOpts) o.apply(hOpts)
} }
code, method := checkLabels(obs) code, method := checkLabels(obs)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
now := time.Now() now := time.Now()
d := newDelegator(w, func(status int) { d := newDelegator(w, func(status int) {
obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds()) exemplarObserve(
obs.With(labels(code, method, r.Method, status, hOpts.extraMethods...)),
time.Since(now).Seconds(),
hOpts.getExemplarFn(r.Context()),
)
}) })
next.ServeHTTP(d, r) next.ServeHTTP(d, r)
}) }
} }
// InstrumentHandlerRequestSize is a middleware that wraps the provided // InstrumentHandlerRequestSize is a middleware that wraps the provided
@ -184,27 +222,34 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
// //
// See the example for InstrumentHandlerDuration for example usage. // See the example for InstrumentHandlerDuration for example usage.
func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc { func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
mwOpts := &option{} hOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(mwOpts) o.apply(hOpts)
} }
code, method := checkLabels(obs) code, method := checkLabels(obs)
if code { if code {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
d := newDelegator(w, nil) d := newDelegator(w, nil)
next.ServeHTTP(d, r) next.ServeHTTP(d, r)
size := computeApproximateRequestSize(r) size := computeApproximateRequestSize(r)
obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size)) exemplarObserve(
}) obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
float64(size),
hOpts.getExemplarFn(r.Context()),
)
}
} }
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
size := computeApproximateRequestSize(r) size := computeApproximateRequestSize(r)
obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size)) exemplarObserve(
}) obs.With(labels(code, method, r.Method, 0, hOpts.extraMethods...)),
float64(size),
hOpts.getExemplarFn(r.Context()),
)
}
} }
// InstrumentHandlerResponseSize is a middleware that wraps the provided // InstrumentHandlerResponseSize is a middleware that wraps the provided
@ -227,9 +272,9 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler,
// //
// See the example for InstrumentHandlerDuration for example usage. // See the example for InstrumentHandlerDuration for example usage.
func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler { func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler {
mwOpts := &option{} hOpts := defaultOptions()
for _, o := range opts { for _, o := range opts {
o(mwOpts) o.apply(hOpts)
} }
code, method := checkLabels(obs) code, method := checkLabels(obs)
@ -237,7 +282,11 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
d := newDelegator(w, nil) d := newDelegator(w, nil)
next.ServeHTTP(d, r) next.ServeHTTP(d, r)
obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written())) exemplarObserve(
obs.With(labels(code, method, r.Method, d.Status(), hOpts.extraMethods...)),
float64(d.Written()),
hOpts.getExemplarFn(r.Context()),
)
}) })
} }
@ -246,7 +295,7 @@ func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler
// Collector does not have a Desc or has more than one Desc or its Desc is // Collector does not have a Desc or has more than one Desc or its Desc is
// invalid. It also panics if the Collector has any non-const, non-curried // invalid. It also panics if the Collector has any non-const, non-curried
// labels that are not named "code" or "method". // labels that are not named "code" or "method".
func checkLabels(c prometheus.Collector) (code bool, method bool) { func checkLabels(c prometheus.Collector) (code, method bool) {
// TODO(beorn7): Remove this hacky way to check for instance labels // TODO(beorn7): Remove this hacky way to check for instance labels
// once Descriptors can have their dimensionality queried. // once Descriptors can have their dimensionality queried.
var ( var (

View File

@ -13,19 +13,46 @@
package promhttp package promhttp
// Option are used to configure a middleware or round tripper.. import (
type Option func(*option) "context"
type option struct { "github.com/prometheus/client_golang/prometheus"
extraMethods []string )
// Option are used to configure both handler (middleware) or round tripper.
type Option interface {
apply(*options)
} }
// options store options for both a handler or round tripper.
type options struct {
extraMethods []string
getExemplarFn func(requestCtx context.Context) prometheus.Labels
}
func defaultOptions() *options {
return &options{getExemplarFn: func(ctx context.Context) prometheus.Labels { return nil }}
}
type optionApplyFunc func(*options)
func (o optionApplyFunc) apply(opt *options) { o(opt) }
// WithExtraMethods adds additional HTTP methods to the list of allowed methods. // WithExtraMethods adds additional HTTP methods to the list of allowed methods.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list. // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list.
// //
// See the example for ExampleInstrumentHandlerWithExtraMethods for example usage. // See the example for ExampleInstrumentHandlerWithExtraMethods for example usage.
func WithExtraMethods(methods ...string) Option { func WithExtraMethods(methods ...string) Option {
return func(o *option) { return optionApplyFunc(func(o *options) {
o.extraMethods = methods o.extraMethods = methods
})
} }
// WithExemplarFromContext adds allows to put a hook to all counter and histogram metrics.
// If the hook function returns non-nil labels, exemplars will be added for that request, otherwise metric
// will get instrumented without exemplar.
func WithExemplarFromContext(getExemplarFn func(requestCtx context.Context) prometheus.Labels) Option {
return optionApplyFunc(func(o *options) {
o.getExemplarFn = getExemplarFn
})
} }

View File

@ -15,8 +15,8 @@ package prometheus
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -289,7 +289,7 @@ func (r *Registry) Register(c Collector) error {
// Is the descriptor valid at all? // Is the descriptor valid at all?
if desc.err != nil { if desc.err != nil {
return fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err) return fmt.Errorf("descriptor %s is invalid: %w", desc, desc.err)
} }
// Is the descID unique? // Is the descID unique?
@ -407,6 +407,14 @@ func (r *Registry) MustRegister(cs ...Collector) {
// Gather implements Gatherer. // Gather implements Gatherer.
func (r *Registry) Gather() ([]*dto.MetricFamily, error) { func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
r.mtx.RLock()
if len(r.collectorsByID) == 0 && len(r.uncheckedCollectors) == 0 {
// Fast path.
r.mtx.RUnlock()
return nil, nil
}
var ( var (
checkedMetricChan = make(chan Metric, capMetricChan) checkedMetricChan = make(chan Metric, capMetricChan)
uncheckedMetricChan = make(chan Metric, capMetricChan) uncheckedMetricChan = make(chan Metric, capMetricChan)
@ -416,7 +424,6 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
registeredDescIDs map[uint64]struct{} // Only used for pedantic checks registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
) )
r.mtx.RLock()
goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors) goroutineBudget := len(r.collectorsByID) + len(r.uncheckedCollectors)
metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName)) metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName))
checkedCollectors := make(chan Collector, len(r.collectorsByID)) checkedCollectors := make(chan Collector, len(r.collectorsByID))
@ -556,7 +563,7 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
// This is intended for use with the textfile collector of the node exporter. // This is intended for use with the textfile collector of the node exporter.
// Note that the node exporter expects the filename to be suffixed with ".prom". // Note that the node exporter expects the filename to be suffixed with ".prom".
func WriteToTextfile(filename string, g Gatherer) error { func WriteToTextfile(filename string, g Gatherer) error {
tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) tmp, err := os.CreateTemp(filepath.Dir(filename), filepath.Base(filename))
if err != nil { if err != nil {
return err return err
} }
@ -575,7 +582,7 @@ func WriteToTextfile(filename string, g Gatherer) error {
return err return err
} }
if err := os.Chmod(tmp.Name(), 0644); err != nil { if err := os.Chmod(tmp.Name(), 0o644); err != nil {
return err return err
} }
return os.Rename(tmp.Name(), filename) return os.Rename(tmp.Name(), filename)
@ -596,7 +603,7 @@ func processMetric(
} }
dtoMetric := &dto.Metric{} dtoMetric := &dto.Metric{}
if err := metric.Write(dtoMetric); err != nil { if err := metric.Write(dtoMetric); err != nil {
return fmt.Errorf("error collecting metric %v: %s", desc, err) return fmt.Errorf("error collecting metric %v: %w", desc, err)
} }
metricFamily, ok := metricFamiliesByName[desc.fqName] metricFamily, ok := metricFamiliesByName[desc.fqName]
if ok { // Existing name. if ok { // Existing name.
@ -718,12 +725,13 @@ func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) {
for i, g := range gs { for i, g := range gs {
mfs, err := g.Gather() mfs, err := g.Gather()
if err != nil { if err != nil {
if multiErr, ok := err.(MultiError); ok { multiErr := MultiError{}
if errors.As(err, &multiErr) {
for _, err := range multiErr { for _, err := range multiErr {
errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) errs = append(errs, fmt.Errorf("[from Gatherer #%d] %w", i+1, err))
} }
} else { } else {
errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err)) errs = append(errs, fmt.Errorf("[from Gatherer #%d] %w", i+1, err))
} }
} }
for _, mf := range mfs { for _, mf := range mfs {
@ -884,11 +892,11 @@ func checkMetricConsistency(
h.Write(separatorByteSlice) h.Write(separatorByteSlice)
// Make sure label pairs are sorted. We depend on it for the consistency // Make sure label pairs are sorted. We depend on it for the consistency
// check. // check.
if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { if !sort.IsSorted(internal.LabelPairSorter(dtoMetric.Label)) {
// We cannot sort dtoMetric.Label in place as it is immutable by contract. // We cannot sort dtoMetric.Label in place as it is immutable by contract.
copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label))
copy(copiedLabels, dtoMetric.Label) copy(copiedLabels, dtoMetric.Label)
sort.Sort(labelPairSorter(copiedLabels)) sort.Sort(internal.LabelPairSorter(copiedLabels))
dtoMetric.Label = copiedLabels dtoMetric.Label = copiedLabels
} }
for _, lp := range dtoMetric.Label { for _, lp := range dtoMetric.Label {
@ -935,7 +943,7 @@ func checkDescConsistency(
metricFamily.GetName(), dtoMetric, desc, metricFamily.GetName(), dtoMetric, desc,
) )
} }
sort.Sort(labelPairSorter(lpsFromDesc)) sort.Sort(internal.LabelPairSorter(lpsFromDesc))
for i, lpFromDesc := range lpsFromDesc { for i, lpFromDesc := range lpsFromDesc {
lpFromMetric := dtoMetric.Label[i] lpFromMetric := dtoMetric.Label[i]
if lpFromDesc.GetName() != lpFromMetric.GetName() || if lpFromDesc.GetName() != lpFromMetric.GetName() ||
@ -948,3 +956,89 @@ func checkDescConsistency(
} }
return nil return nil
} }
var _ TransactionalGatherer = &MultiTRegistry{}
// MultiTRegistry is a TransactionalGatherer that joins gathered metrics from multiple
// transactional gatherers.
//
// It is caller responsibility to ensure two registries have mutually exclusive metric families,
// no deduplication will happen.
type MultiTRegistry struct {
tGatherers []TransactionalGatherer
}
// NewMultiTRegistry creates MultiTRegistry.
func NewMultiTRegistry(tGatherers ...TransactionalGatherer) *MultiTRegistry {
return &MultiTRegistry{
tGatherers: tGatherers,
}
}
// Gather implements TransactionalGatherer interface.
func (r *MultiTRegistry) Gather() (mfs []*dto.MetricFamily, done func(), err error) {
errs := MultiError{}
dFns := make([]func(), 0, len(r.tGatherers))
// TODO(bwplotka): Implement concurrency for those?
for _, g := range r.tGatherers {
// TODO(bwplotka): Check for duplicates?
m, d, err := g.Gather()
errs.Append(err)
mfs = append(mfs, m...)
dFns = append(dFns, d)
}
// TODO(bwplotka): Consider sort in place, given metric family in gather is sorted already.
sort.Slice(mfs, func(i, j int) bool {
return *mfs[i].Name < *mfs[j].Name
})
return mfs, func() {
for _, d := range dFns {
d()
}
}, errs.MaybeUnwrap()
}
// TransactionalGatherer represents transactional gatherer that can be triggered to notify gatherer that memory
// used by metric family is no longer used by a caller. This allows implementations with cache.
type TransactionalGatherer interface {
// Gather returns metrics in a lexicographically sorted slice
// of uniquely named MetricFamily protobufs. Gather ensures that the
// returned slice is valid and self-consistent so that it can be used
// for valid exposition. As an exception to the strict consistency
// requirements described for metric.Desc, Gather will tolerate
// different sets of label names for metrics of the same metric family.
//
// Even if an error occurs, Gather attempts to gather as many metrics as
// possible. Hence, if a non-nil error is returned, the returned
// MetricFamily slice could be nil (in case of a fatal error that
// prevented any meaningful metric collection) or contain a number of
// MetricFamily protobufs, some of which might be incomplete, and some
// might be missing altogether. The returned error (which might be a
// MultiError) explains the details. Note that this is mostly useful for
// debugging purposes. If the gathered protobufs are to be used for
// exposition in actual monitoring, it is almost always better to not
// expose an incomplete result and instead disregard the returned
// MetricFamily protobufs in case the returned error is non-nil.
//
// Important: done is expected to be triggered (even if the error occurs!)
// once caller does not need returned slice of dto.MetricFamily.
Gather() (_ []*dto.MetricFamily, done func(), err error)
}
// ToTransactionalGatherer transforms Gatherer to transactional one with noop as done function.
func ToTransactionalGatherer(g Gatherer) TransactionalGatherer {
return &noTransactionGatherer{g: g}
}
type noTransactionGatherer struct {
g Gatherer
}
// Gather implements TransactionalGatherer interface.
func (g *noTransactionGatherer) Gather() (_ []*dto.MetricFamily, done func(), err error) {
mfs, err := g.g.Gather()
return mfs, func() {}, err
}

View File

@ -23,6 +23,8 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"github.com/prometheus/client_golang/prometheus/internal"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
) )
@ -38,6 +40,23 @@ const (
UntypedValue UntypedValue
) )
var (
CounterMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_COUNTER; return &d }()
GaugeMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_GAUGE; return &d }()
UntypedMetricTypePtr = func() *dto.MetricType { d := dto.MetricType_UNTYPED; return &d }()
)
func (v ValueType) ToDTO() *dto.MetricType {
switch v {
case CounterValue:
return CounterMetricTypePtr
case GaugeValue:
return GaugeMetricTypePtr
default:
return UntypedMetricTypePtr
}
}
// valueFunc is a generic metric for simple values retrieved on collect time // valueFunc is a generic metric for simple values retrieved on collect time
// from a function. It implements Metric and Collector. Its effective type is // from a function. It implements Metric and Collector. Its effective type is
// determined by ValueType. This is a low-level building block used by the // determined by ValueType. This is a low-level building block used by the
@ -91,11 +110,15 @@ func NewConstMetric(desc *Desc, valueType ValueType, value float64, labelValues
if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil { if err := validateLabelValues(labelValues, len(desc.variableLabels)); err != nil {
return nil, err return nil, err
} }
metric := &dto.Metric{}
if err := populateMetric(valueType, value, MakeLabelPairs(desc, labelValues), nil, metric); err != nil {
return nil, err
}
return &constMetric{ return &constMetric{
desc: desc, desc: desc,
valType: valueType, metric: metric,
val: value,
labelPairs: MakeLabelPairs(desc, labelValues),
}, nil }, nil
} }
@ -111,9 +134,7 @@ func MustNewConstMetric(desc *Desc, valueType ValueType, value float64, labelVal
type constMetric struct { type constMetric struct {
desc *Desc desc *Desc
valType ValueType metric *dto.Metric
val float64
labelPairs []*dto.LabelPair
} }
func (m *constMetric) Desc() *Desc { func (m *constMetric) Desc() *Desc {
@ -121,7 +142,11 @@ func (m *constMetric) Desc() *Desc {
} }
func (m *constMetric) Write(out *dto.Metric) error { func (m *constMetric) Write(out *dto.Metric) error {
return populateMetric(m.valType, m.val, m.labelPairs, nil, out) out.Label = m.metric.Label
out.Counter = m.metric.Counter
out.Gauge = m.metric.Gauge
out.Untyped = m.metric.Untyped
return nil
} }
func populateMetric( func populateMetric(
@ -170,12 +195,12 @@ func MakeLabelPairs(desc *Desc, labelValues []string) []*dto.LabelPair {
}) })
} }
labelPairs = append(labelPairs, desc.constLabelPairs...) labelPairs = append(labelPairs, desc.constLabelPairs...)
sort.Sort(labelPairSorter(labelPairs)) sort.Sort(internal.LabelPairSorter(labelPairs))
return labelPairs return labelPairs
} }
// ExemplarMaxRunes is the max total number of runes allowed in exemplar labels. // ExemplarMaxRunes is the max total number of runes allowed in exemplar labels.
const ExemplarMaxRunes = 64 const ExemplarMaxRunes = 128
// newExemplar creates a new dto.Exemplar from the provided values. An error is // newExemplar creates a new dto.Exemplar from the provided values. An error is
// returned if any of the label names or values are invalid or if the total // returned if any of the label names or values are invalid or if the total

View File

@ -99,6 +99,16 @@ func (m *MetricVec) Delete(labels Labels) bool {
return m.metricMap.deleteByHashWithLabels(h, labels, m.curry) return m.metricMap.deleteByHashWithLabels(h, labels, m.curry)
} }
// DeletePartialMatch deletes all metrics where the variable labels contain all of those
// passed in as labels. The order of the labels does not matter.
// It returns the number of metrics deleted.
//
// Note that curried labels will never be matched if deleting from the curried vector.
// To match curried labels with DeletePartialMatch, it must be called on the base vector.
func (m *MetricVec) DeletePartialMatch(labels Labels) int {
return m.metricMap.deleteByLabels(labels, m.curry)
}
// Without explicit forwarding of Describe, Collect, Reset, those methods won't // Without explicit forwarding of Describe, Collect, Reset, those methods won't
// show up in GoDoc. // show up in GoDoc.
@ -381,6 +391,82 @@ func (m *metricMap) deleteByHashWithLabels(
return true return true
} }
// deleteByLabels deletes a metric if the given labels are present in the metric.
func (m *metricMap) deleteByLabels(labels Labels, curry []curriedLabelValue) int {
m.mtx.Lock()
defer m.mtx.Unlock()
var numDeleted int
for h, metrics := range m.metrics {
i := findMetricWithPartialLabels(m.desc, metrics, labels, curry)
if i >= len(metrics) {
// Didn't find matching labels in this metric slice.
continue
}
delete(m.metrics, h)
numDeleted++
}
return numDeleted
}
// findMetricWithPartialLabel returns the index of the matching metric or
// len(metrics) if not found.
func findMetricWithPartialLabels(
desc *Desc, metrics []metricWithLabelValues, labels Labels, curry []curriedLabelValue,
) int {
for i, metric := range metrics {
if matchPartialLabels(desc, metric.values, labels, curry) {
return i
}
}
return len(metrics)
}
// indexOf searches the given slice of strings for the target string and returns
// the index or len(items) as well as a boolean whether the search succeeded.
func indexOf(target string, items []string) (int, bool) {
for i, l := range items {
if l == target {
return i, true
}
}
return len(items), false
}
// valueMatchesVariableOrCurriedValue determines if a value was previously curried,
// and returns whether it matches either the "base" value or the curried value accordingly.
// It also indicates whether the match is against a curried or uncurried value.
func valueMatchesVariableOrCurriedValue(targetValue string, index int, values []string, curry []curriedLabelValue) (bool, bool) {
for _, curriedValue := range curry {
if curriedValue.index == index {
// This label was curried. See if the curried value matches our target.
return curriedValue.value == targetValue, true
}
}
// This label was not curried. See if the current value matches our target label.
return values[index] == targetValue, false
}
// matchPartialLabels searches the current metric and returns whether all of the target label:value pairs are present.
func matchPartialLabels(desc *Desc, values []string, labels Labels, curry []curriedLabelValue) bool {
for l, v := range labels {
// Check if the target label exists in our metrics and get the index.
varLabelIndex, validLabel := indexOf(l, desc.variableLabels)
if validLabel {
// Check the value of that label against the target value.
// We don't consider curried values in partial matches.
matches, curried := valueMatchesVariableOrCurriedValue(v, varLabelIndex, values, curry)
if matches && !curried {
continue
}
}
return false
}
return true
}
// getOrCreateMetricWithLabelValues retrieves the metric by hash and label value // getOrCreateMetricWithLabelValues retrieves the metric by hash and label value
// or creates it and returns the new one. // or creates it and returns the new one.
// //
@ -485,7 +571,7 @@ func findMetricWithLabels(
return len(metrics) return len(metrics)
} }
func matchLabelValues(values []string, lvs []string, curry []curriedLabelValue) bool { func matchLabelValues(values, lvs []string, curry []curriedLabelValue) bool {
if len(values) != len(lvs)+len(curry) { if len(values) != len(lvs)+len(curry) {
return false return false
} }

View File

@ -21,6 +21,8 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
"github.com/prometheus/client_golang/prometheus/internal"
) )
// WrapRegistererWith returns a Registerer wrapping the provided // WrapRegistererWith returns a Registerer wrapping the provided
@ -182,7 +184,7 @@ func (m *wrappingMetric) Write(out *dto.Metric) error {
Value: proto.String(lv), Value: proto.String(lv),
}) })
} }
sort.Sort(labelPairSorter(out.Label)) sort.Sort(internal.LabelPairSorter(out.Label))
return nil return nil
} }

View File

@ -12,6 +12,7 @@
// limitations under the License. // limitations under the License.
// Build only when actually fuzzing // Build only when actually fuzzing
//go:build gofuzz
// +build gofuzz // +build gofuzz
package expfmt package expfmt

View File

@ -22,7 +22,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/golang/protobuf/ptypes"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
dto "github.com/prometheus/client_model/go" dto "github.com/prometheus/client_model/go"
@ -473,10 +472,11 @@ func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
if err != nil { if err != nil {
return written, err return written, err
} }
ts, err := ptypes.Timestamp((*e).Timestamp) err = (*e).Timestamp.CheckValid()
if err != nil { if err != nil {
return written, err return written, err
} }
ts := (*e).Timestamp.AsTime()
// TODO(beorn7): Format this directly from components of ts to // TODO(beorn7): Format this directly from components of ts to
// avoid overflow/underflow and precision issues of the float // avoid overflow/underflow and precision issues of the float
// conversion. // conversion.

Some files were not shown because too many files have changed in this diff Show More