Compare commits
No commits in common. "build-test" and "bind-and-fetch" have entirely different histories.
build-test
...
bind-and-f
11
go.mod
Normal file
11
go.mod
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
module github.com/xoe-labs/ldap/v0
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/caddyserver/caddy v1.0.5
|
||||||
|
github.com/coredns/coredns v1.6.9
|
||||||
|
github.com/miekg/dns v1.1.29
|
||||||
|
github.com/prometheus/client_golang v1.6.0
|
||||||
|
gopkg.in/ldap.v3 v3.1.0
|
||||||
|
)
|
587
go.sum
Normal file
587
go.sum
Normal file
@ -0,0 +1,587 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg=
|
||||||
|
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||||
|
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
|
github.com/Azure/azure-sdk-for-go v32.6.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.10.0/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
|
||||||
|
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/DataDog/datadog-go v3.3.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
|
github.com/DataDog/zstd v1.3.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
|
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
||||||
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/sarama v1.21.0/go.mod h1:yuqtN/pe8cXRWG5zPaO7hCfNJp5MwmkoJEoLjkm5tCQ=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k=
|
||||||
|
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
|
||||||
|
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/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
|
||||||
|
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/aws/aws-sdk-go v1.29.29/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
|
||||||
|
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||||
|
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.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/caddyserver/caddy v1.0.5 h1:5B1Hs0UF2x2tggr2X9jL2qOZtDXbIWQb9YLbmlxHSuM=
|
||||||
|
github.com/caddyserver/caddy v1.0.5/go.mod h1:AnFHB+/MrgRC+mJAvuAgQ38ePzw+wKeW0wzENpdQQKY=
|
||||||
|
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
|
github.com/coredns/coredns v1.6.9 h1:i3c8XAY6f9jzxtUUx07WH2/ft0RXOrP9zIRd4YODGOQ=
|
||||||
|
github.com/coredns/coredns v1.6.9/go.mod h1:KTV/oAc4nYoKBdQ6aOFI+m4tnZeh4iySMvJconHhF/c=
|
||||||
|
github.com/coredns/federation v0.0.0-20190818181423-e032b096babe/go.mod h1:MoqTEFX8GlnKkyq8eBCF94VzkNAOgjdlCJ+Pz/oCLPk=
|
||||||
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||||
|
github.com/coreos/license-bill-of-materials v0.0.0-20190913234955-13baff47494e/go.mod h1:4xMOusJ7xxc84WclVxKT8+lNfGYDwojOUC2OQNCwcj4=
|
||||||
|
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
|
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
|
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
|
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||||
|
github.com/dnstap/golang-dnstap v0.0.0-20170829151710-2cf77a2b5e11/go.mod h1:s1PfVYYVmTMgCSPtho4LKBDecEHJWtiVDPNv78Z985U=
|
||||||
|
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||||
|
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/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-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-20170405201442-c4fc26588b6e/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.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.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
|
github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
|
||||||
|
github.com/farsightsec/golang-framestream v0.0.0-20181102145529-8a0cb8ba8710/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
|
||||||
|
github.com/go-acme/lego/v3 v3.2.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
|
||||||
|
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||||
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
|
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
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-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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||||
|
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||||
|
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||||
|
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||||
|
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||||
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
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.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
|
||||||
|
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
|
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
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/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.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||||
|
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
|
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||||
|
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||||
|
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||||
|
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/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
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/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
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.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||||
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
|
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
|
||||||
|
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/infobloxopen/go-trees v0.0.0-20190313150506-2af4e13f9062/go.mod h1:PcNJqIlcX/dj3DTG/+QQnRvSgTMG6CLpRMjWcv4+J6w=
|
||||||
|
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
|
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||||
|
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.2/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/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||||
|
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||||
|
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||||
|
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
|
||||||
|
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
|
||||||
|
github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
|
||||||
|
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
|
||||||
|
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
|
||||||
|
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
|
||||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
|
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/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
|
||||||
|
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||||
|
github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
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/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||||
|
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||||
|
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||||
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
|
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
||||||
|
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
||||||
|
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
|
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.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
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.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/openzipkin-contrib/zipkin-go-opentracing v0.3.5/go.mod h1:uVHyebswE1cCXr2A73cRM2frx5ld1RJUCJkFNZ90ZiI=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
|
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
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.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||||
|
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||||
|
github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
|
||||||
|
github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/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-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||||
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
|
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||||
|
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||||
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
|
github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
|
||||||
|
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
|
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
||||||
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
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/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
|
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/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.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
|
||||||
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
|
||||||
|
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||||
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
|
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.etcd.io/etcd v0.5.0-alpha.5.0.20200306183522-221f0cc107cb/go.mod h1:VZB9Yx4s43MHItytoe8jcvaEFEgF2QzHDZGfQ/XQjvQ=
|
||||||
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||||
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo=
|
||||||
|
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/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-20190813141303-74dc4d7220e7/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-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/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-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||||
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||||
|
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/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.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
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-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
|
||||||
|
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
|
||||||
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200306153348-d950eab6f860 h1:QmnwU8dKvY8c/vZikd2jhBNwrrGS5qeyK/2Aeeh9Grk=
|
||||||
|
google.golang.org/genproto v0.0.0-20200306153348-d950eab6f860/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
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.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
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.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
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.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
|
||||||
|
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||||
|
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-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
gopkg.in/DataDog/dd-trace-go.v1 v1.22.0/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
|
||||||
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||||
|
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-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE=
|
||||||
|
gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ=
|
||||||
|
gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
|
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
|
||||||
|
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/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 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
k8s.io/api v0.17.4 h1:HbwOhDapkguO8lTAE8OX3hdF2qp8GtpC9CW/MQATXXo=
|
||||||
|
k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA=
|
||||||
|
k8s.io/apimachinery v0.17.4 h1:UzM+38cPUJnzqSQ+E1PY4YxMHIzQyCg29LOoGfo79Zw=
|
||||||
|
k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g=
|
||||||
|
k8s.io/client-go v0.17.4 h1:VVdVbpTY70jiNHS1eiFkUt7ZIJX3txd29nDxxXH4en8=
|
||||||
|
k8s.io/client-go v0.17.4/go.mod h1:ouF6o5pz3is8qU0/qYL2RnoxOPqgfuidYLowytyLJmc=
|
||||||
|
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
|
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
|
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||||
|
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||||
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||||
|
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||||
|
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||||
|
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||||
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
Normal file
20
vendor/github.com/beorn7/perks/LICENSE
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
Copyright (C) 2013 Blake Mizerany
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
2388
vendor/github.com/beorn7/perks/quantile/exampledata.txt
generated
vendored
Normal file
2388
vendor/github.com/beorn7/perks/quantile/exampledata.txt
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
316
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
Normal file
316
vendor/github.com/beorn7/perks/quantile/stream.go
generated
vendored
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
// Package quantile computes approximate quantiles over an unbounded data
|
||||||
|
// stream within low memory and CPU bounds.
|
||||||
|
//
|
||||||
|
// A small amount of accuracy is traded to achieve the above properties.
|
||||||
|
//
|
||||||
|
// Multiple streams can be merged before calling Query to generate a single set
|
||||||
|
// of results. This is meaningful when the streams represent the same type of
|
||||||
|
// data. See Merge and Samples.
|
||||||
|
//
|
||||||
|
// For more detailed information about the algorithm used, see:
|
||||||
|
//
|
||||||
|
// Effective Computation of Biased Quantiles over Data Streams
|
||||||
|
//
|
||||||
|
// http://www.cs.rutgers.edu/~muthu/bquant.pdf
|
||||||
|
package quantile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Sample holds an observed value and meta information for compression. JSON
|
||||||
|
// tags have been added for convenience.
|
||||||
|
type Sample struct {
|
||||||
|
Value float64 `json:",string"`
|
||||||
|
Width float64 `json:",string"`
|
||||||
|
Delta float64 `json:",string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samples represents a slice of samples. It implements sort.Interface.
|
||||||
|
type Samples []Sample
|
||||||
|
|
||||||
|
func (a Samples) Len() int { return len(a) }
|
||||||
|
func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
||||||
|
func (a Samples) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
|
||||||
|
type invariant func(s *stream, r float64) float64
|
||||||
|
|
||||||
|
// NewLowBiased returns an initialized Stream for low-biased quantiles
|
||||||
|
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
|
||||||
|
// error guarantees can still be given even for the lower ranks of the data
|
||||||
|
// distribution.
|
||||||
|
//
|
||||||
|
// The provided epsilon is a relative error, i.e. the true quantile of a value
|
||||||
|
// returned by a query is guaranteed to be within (1±Epsilon)*Quantile.
|
||||||
|
//
|
||||||
|
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
|
||||||
|
// properties.
|
||||||
|
func NewLowBiased(epsilon float64) *Stream {
|
||||||
|
ƒ := func(s *stream, r float64) float64 {
|
||||||
|
return 2 * epsilon * r
|
||||||
|
}
|
||||||
|
return newStream(ƒ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHighBiased returns an initialized Stream for high-biased quantiles
|
||||||
|
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
|
||||||
|
// error guarantees can still be given even for the higher ranks of the data
|
||||||
|
// distribution.
|
||||||
|
//
|
||||||
|
// The provided epsilon is a relative error, i.e. the true quantile of a value
|
||||||
|
// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile).
|
||||||
|
//
|
||||||
|
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
|
||||||
|
// properties.
|
||||||
|
func NewHighBiased(epsilon float64) *Stream {
|
||||||
|
ƒ := func(s *stream, r float64) float64 {
|
||||||
|
return 2 * epsilon * (s.n - r)
|
||||||
|
}
|
||||||
|
return newStream(ƒ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTargeted returns an initialized Stream concerned with a particular set of
|
||||||
|
// quantile values that are supplied a priori. Knowing these a priori reduces
|
||||||
|
// space and computation time. The targets map maps the desired quantiles to
|
||||||
|
// their absolute errors, i.e. the true quantile of a value returned by a query
|
||||||
|
// is guaranteed to be within (Quantile±Epsilon).
|
||||||
|
//
|
||||||
|
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
|
||||||
|
func NewTargeted(targetMap map[float64]float64) *Stream {
|
||||||
|
// Convert map to slice to avoid slow iterations on a map.
|
||||||
|
// ƒ is called on the hot path, so converting the map to a slice
|
||||||
|
// beforehand results in significant CPU savings.
|
||||||
|
targets := targetMapToSlice(targetMap)
|
||||||
|
|
||||||
|
ƒ := func(s *stream, r float64) float64 {
|
||||||
|
var m = math.MaxFloat64
|
||||||
|
var f float64
|
||||||
|
for _, t := range targets {
|
||||||
|
if t.quantile*s.n <= r {
|
||||||
|
f = (2 * t.epsilon * r) / t.quantile
|
||||||
|
} else {
|
||||||
|
f = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile)
|
||||||
|
}
|
||||||
|
if f < m {
|
||||||
|
m = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
return newStream(ƒ)
|
||||||
|
}
|
||||||
|
|
||||||
|
type target struct {
|
||||||
|
quantile float64
|
||||||
|
epsilon float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetMapToSlice(targetMap map[float64]float64) []target {
|
||||||
|
targets := make([]target, 0, len(targetMap))
|
||||||
|
|
||||||
|
for quantile, epsilon := range targetMap {
|
||||||
|
t := target{
|
||||||
|
quantile: quantile,
|
||||||
|
epsilon: epsilon,
|
||||||
|
}
|
||||||
|
targets = append(targets, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return targets
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream computes quantiles for a stream of float64s. It is not thread-safe by
|
||||||
|
// design. Take care when using across multiple goroutines.
|
||||||
|
type Stream struct {
|
||||||
|
*stream
|
||||||
|
b Samples
|
||||||
|
sorted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStream(ƒ invariant) *Stream {
|
||||||
|
x := &stream{ƒ: ƒ}
|
||||||
|
return &Stream{x, make(Samples, 0, 500), true}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert inserts v into the stream.
|
||||||
|
func (s *Stream) Insert(v float64) {
|
||||||
|
s.insert(Sample{Value: v, Width: 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) insert(sample Sample) {
|
||||||
|
s.b = append(s.b, sample)
|
||||||
|
s.sorted = false
|
||||||
|
if len(s.b) == cap(s.b) {
|
||||||
|
s.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query returns the computed qth percentiles value. If s was created with
|
||||||
|
// NewTargeted, and q is not in the set of quantiles provided a priori, Query
|
||||||
|
// will return an unspecified result.
|
||||||
|
func (s *Stream) Query(q float64) float64 {
|
||||||
|
if !s.flushed() {
|
||||||
|
// Fast path when there hasn't been enough data for a flush;
|
||||||
|
// this also yields better accuracy for small sets of data.
|
||||||
|
l := len(s.b)
|
||||||
|
if l == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
i := int(math.Ceil(float64(l) * q))
|
||||||
|
if i > 0 {
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
s.maybeSort()
|
||||||
|
return s.b[i].Value
|
||||||
|
}
|
||||||
|
s.flush()
|
||||||
|
return s.stream.query(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges samples into the underlying streams samples. This is handy when
|
||||||
|
// merging multiple streams from separate threads, database shards, etc.
|
||||||
|
//
|
||||||
|
// ATTENTION: This method is broken and does not yield correct results. The
|
||||||
|
// underlying algorithm is not capable of merging streams correctly.
|
||||||
|
func (s *Stream) Merge(samples Samples) {
|
||||||
|
sort.Sort(samples)
|
||||||
|
s.stream.merge(samples)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset reinitializes and clears the list reusing the samples buffer memory.
|
||||||
|
func (s *Stream) Reset() {
|
||||||
|
s.stream.reset()
|
||||||
|
s.b = s.b[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Samples returns stream samples held by s.
|
||||||
|
func (s *Stream) Samples() Samples {
|
||||||
|
if !s.flushed() {
|
||||||
|
return s.b
|
||||||
|
}
|
||||||
|
s.flush()
|
||||||
|
return s.stream.samples()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the total number of samples observed in the stream
|
||||||
|
// since initialization.
|
||||||
|
func (s *Stream) Count() int {
|
||||||
|
return len(s.b) + s.stream.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) flush() {
|
||||||
|
s.maybeSort()
|
||||||
|
s.stream.merge(s.b)
|
||||||
|
s.b = s.b[:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) maybeSort() {
|
||||||
|
if !s.sorted {
|
||||||
|
s.sorted = true
|
||||||
|
sort.Sort(s.b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Stream) flushed() bool {
|
||||||
|
return len(s.stream.l) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type stream struct {
|
||||||
|
n float64
|
||||||
|
l []Sample
|
||||||
|
ƒ invariant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) reset() {
|
||||||
|
s.l = s.l[:0]
|
||||||
|
s.n = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) insert(v float64) {
|
||||||
|
s.merge(Samples{{v, 1, 0}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) merge(samples Samples) {
|
||||||
|
// TODO(beorn7): This tries to merge not only individual samples, but
|
||||||
|
// whole summaries. The paper doesn't mention merging summaries at
|
||||||
|
// all. Unittests show that the merging is inaccurate. Find out how to
|
||||||
|
// do merges properly.
|
||||||
|
var r float64
|
||||||
|
i := 0
|
||||||
|
for _, sample := range samples {
|
||||||
|
for ; i < len(s.l); i++ {
|
||||||
|
c := s.l[i]
|
||||||
|
if c.Value > sample.Value {
|
||||||
|
// Insert at position i.
|
||||||
|
s.l = append(s.l, Sample{})
|
||||||
|
copy(s.l[i+1:], s.l[i:])
|
||||||
|
s.l[i] = Sample{
|
||||||
|
sample.Value,
|
||||||
|
sample.Width,
|
||||||
|
math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1),
|
||||||
|
// TODO(beorn7): How to calculate delta correctly?
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
goto inserted
|
||||||
|
}
|
||||||
|
r += c.Width
|
||||||
|
}
|
||||||
|
s.l = append(s.l, Sample{sample.Value, sample.Width, 0})
|
||||||
|
i++
|
||||||
|
inserted:
|
||||||
|
s.n += sample.Width
|
||||||
|
r += sample.Width
|
||||||
|
}
|
||||||
|
s.compress()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) count() int {
|
||||||
|
return int(s.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) query(q float64) float64 {
|
||||||
|
t := math.Ceil(q * s.n)
|
||||||
|
t += math.Ceil(s.ƒ(s, t) / 2)
|
||||||
|
p := s.l[0]
|
||||||
|
var r float64
|
||||||
|
for _, c := range s.l[1:] {
|
||||||
|
r += p.Width
|
||||||
|
if r+c.Width+c.Delta > t {
|
||||||
|
return p.Value
|
||||||
|
}
|
||||||
|
p = c
|
||||||
|
}
|
||||||
|
return p.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) compress() {
|
||||||
|
if len(s.l) < 2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x := s.l[len(s.l)-1]
|
||||||
|
xi := len(s.l) - 1
|
||||||
|
r := s.n - 1 - x.Width
|
||||||
|
|
||||||
|
for i := len(s.l) - 2; i >= 0; i-- {
|
||||||
|
c := s.l[i]
|
||||||
|
if c.Width+x.Width+x.Delta <= s.ƒ(s, r) {
|
||||||
|
x.Width += c.Width
|
||||||
|
s.l[xi] = x
|
||||||
|
// Remove element at i.
|
||||||
|
copy(s.l[i:], s.l[i+1:])
|
||||||
|
s.l = s.l[:len(s.l)-1]
|
||||||
|
xi -= 1
|
||||||
|
} else {
|
||||||
|
x = c
|
||||||
|
xi = i
|
||||||
|
}
|
||||||
|
r -= c.Width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stream) samples() Samples {
|
||||||
|
samples := make(Samples, len(s.l))
|
||||||
|
copy(samples, s.l)
|
||||||
|
return samples
|
||||||
|
}
|
21
vendor/github.com/caddyserver/caddy/.gitattributes
generated
vendored
Normal file
21
vendor/github.com/caddyserver/caddy/.gitattributes
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# shell scripts should not use tabs to indent!
|
||||||
|
*.bash text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.sh text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
|
||||||
|
# files for systemd (shell-similar)
|
||||||
|
*.path text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.service text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.timer text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
|
||||||
|
# go fmt will enforce this, but in case a user has not called "go fmt" allow GIT to catch this:
|
||||||
|
*.go text eol=lf core.whitespace whitespace=indent-with-non-tab,trailing-space,tabwidth=4
|
||||||
|
go.mod text eol=lf
|
||||||
|
go.sum text eol=lf
|
||||||
|
|
||||||
|
*.txt text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.tpl text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.htm text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.html text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.md text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
*.yml text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
|
||||||
|
.git* text eol=auto core.whitespace whitespace=trailing-space
|
22
vendor/github.com/caddyserver/caddy/.gitignore
generated
vendored
Normal file
22
vendor/github.com/caddyserver/caddy/.gitignore
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
_gitignore/
|
||||||
|
Vagrantfile
|
||||||
|
.vagrant/
|
||||||
|
/.idea
|
||||||
|
|
||||||
|
dist/builds/
|
||||||
|
dist/release/
|
||||||
|
|
||||||
|
error.log
|
||||||
|
access.log
|
||||||
|
|
||||||
|
/*.conf
|
||||||
|
Caddyfile
|
||||||
|
!caddyfile/
|
||||||
|
|
||||||
|
og_static/
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
*.bat
|
201
vendor/github.com/caddyserver/caddy/LICENSE.txt
generated
vendored
Normal file
201
vendor/github.com/caddyserver/caddy/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
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.
|
218
vendor/github.com/caddyserver/caddy/README.md
generated
vendored
Normal file
218
vendor/github.com/caddyserver/caddy/README.md
generated
vendored
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="https://caddyserver.com"><img src="https://user-images.githubusercontent.com/1128849/36338535-05fb646a-136f-11e8-987b-e6901e717d5a.png" alt="Caddy" width="450"></a>
|
||||||
|
</p>
|
||||||
|
<h3 align="center">Every Site on HTTPS <!-- Serve Confidently --></h3>
|
||||||
|
<p align="center">Caddy is a general-purpose HTTP/2 web server that serves HTTPS by default.</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://dev.azure.com/mholt-dev/Caddy/_build?definitionId=5"><img src="https://img.shields.io/azure-devops/build/mholt-dev/afec6074-9842-457f-98cf-69df6adbbf2e/5/master.svg?label=cross-platform%20tests"></a>
|
||||||
|
<a href="https://godoc.org/github.com/caddyserver/caddy"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"></a>
|
||||||
|
<a href="https://goreportcard.com/report/caddyserver/caddy"><img src="https://goreportcard.com/badge/github.com/caddyserver/caddy"></a>
|
||||||
|
<br>
|
||||||
|
<a href="https://twitter.com/caddyserver" title="@caddyserver on Twitter"><img src="https://img.shields.io/badge/twitter-@caddyserver-55acee.svg" alt="@caddyserver on Twitter"></a>
|
||||||
|
<a href="https://caddy.community" title="Caddy Forum"><img src="https://img.shields.io/badge/community-forum-ff69b4.svg" alt="Caddy Forum"></a>
|
||||||
|
<a href="https://sourcegraph.com/github.com/caddyserver/caddy?badge" title="Caddy on Sourcegraph"><img src="https://sourcegraph.com/github.com/caddyserver/caddy/-/badge.svg" alt="Caddy on Sourcegraph"></a>
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://caddyserver.com/download">Download</a> ·
|
||||||
|
<a href="https://caddyserver.com/docs">Documentation</a> ·
|
||||||
|
<a href="https://caddy.community">Community</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Caddy is a **production-ready** open-source web server that is fast, easy to use, and makes you more productive.
|
||||||
|
|
||||||
|
Available for Windows, Mac, Linux, BSD, Solaris, and [Android](https://github.com/caddyserver/caddy/wiki/Running-Caddy-on-Android).
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<b>Thanks to our special sponsor:</b>
|
||||||
|
<br><br>
|
||||||
|
<a href="https://relicabackup.com"><img src="https://caddyserver.com/resources/images/sponsors/relica.png" width="220" alt="Relica - Cross-platform file backup to the cloud, local disks, or other computers"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Menu
|
||||||
|
|
||||||
|
- [Features](#features)
|
||||||
|
- [Install](#install)
|
||||||
|
- [Quick Start](#quick-start)
|
||||||
|
- [Running in Production](#running-in-production)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
- [Donors](#donors)
|
||||||
|
- [About the Project](#about-the-project)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Easy configuration** with the Caddyfile
|
||||||
|
- **Automatic HTTPS** on by default (via [Let's Encrypt](https://letsencrypt.org))
|
||||||
|
- **HTTP/2** by default
|
||||||
|
- **Virtual hosting** so multiple sites just work
|
||||||
|
- Experimental **QUIC support** for cutting-edge transmissions
|
||||||
|
- TLS session ticket **key rotation** for more secure connections
|
||||||
|
- **Extensible with plugins** because a convenient web server is a helpful one
|
||||||
|
- **Runs anywhere** with **no external dependencies** (not even libc)
|
||||||
|
|
||||||
|
[See a more complete list of features built into Caddy.](https://caddyserver.com/features) On top of all those, Caddy does even more with plugins: choose which plugins you want at [download](https://caddyserver.com/download).
|
||||||
|
|
||||||
|
Altogether, Caddy can do things other web servers simply cannot do. Its features and plugins save you time and mistakes, and will cheer you up. Your Caddy instance takes care of the details for you!
|
||||||
|
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<b>Powered by</b>
|
||||||
|
<br>
|
||||||
|
<a href="https://github.com/mholt/certmagic"><img src="https://user-images.githubusercontent.com/1128849/49704830-49d37200-fbd5-11e8-8385-767e0cd033c3.png" alt="CertMagic" width="250"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Caddy binaries have no dependencies and are available for every platform. Get Caddy any of these ways:
|
||||||
|
|
||||||
|
- **[Download page](https://caddyserver.com/download)** (RECOMMENDED) allows you to customize your build in the browser
|
||||||
|
- **[Latest release](https://github.com/caddyserver/caddy/releases/latest)** for pre-built, vanilla binaries
|
||||||
|
- **[AWS Marketplace](https://aws.amazon.com/marketplace/pp/B07J1WNK75?qid=1539015041932&sr=0-1&ref_=srh_res_product_title&cl_spe=C)** makes it easy to deploy directly to your cloud environment. <a href="https://aws.amazon.com/marketplace/pp/B07J1WNK75?qid=1539015041932&sr=0-1&ref_=srh_res_product_title&cl_spe=C" target="_blank">
|
||||||
|
<img src="https://s3.amazonaws.com/cloudformation-examples/cloudformation-launch-stack.png" alt="Get Caddy on the AWS Marketplace" height="25"/></a>
|
||||||
|
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
To build from source you need **[Git](https://git-scm.com/downloads)** and **[Go](https://golang.org/doc/install)** (1.13 or newer).
|
||||||
|
|
||||||
|
**To build Caddy without plugins:**
|
||||||
|
|
||||||
|
- Run `go get github.com/caddyserver/caddy/caddy`
|
||||||
|
|
||||||
|
Caddy will be installed to your `$GOPATH/bin` folder.
|
||||||
|
|
||||||
|
With these instructions, the binary will not have embedded version information (see [golang/go#29228](https://github.com/golang/go/issues/29228)), but it is fine for a quick start.
|
||||||
|
|
||||||
|
**To build Caddy with plugins (and with version information):**
|
||||||
|
|
||||||
|
There is no need to modify the Caddy code to build it with plugins. We will create a simple Go module with our own `main()` that you can use to make custom Caddy builds.
|
||||||
|
- Create a new folder anywhere and within create a Go file (with an extension of `.go`, such as `main.go`) with the contents below, adjusting to import the plugins you want to include:
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caddyserver/caddy/caddy/caddymain"
|
||||||
|
|
||||||
|
// plug in plugins here, for example:
|
||||||
|
// _ "import/path/here"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// optional: disable telemetry
|
||||||
|
// caddymain.EnableTelemetry = false
|
||||||
|
caddymain.Run()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. `go mod init caddy`
|
||||||
|
4. Run `go get github.com/caddyserver/caddy`
|
||||||
|
5. `go install` will then create your binary at `$GOPATH/bin`, or `go build` will put it in the current directory.
|
||||||
|
|
||||||
|
**To install Caddy's source code for development:**
|
||||||
|
|
||||||
|
- Run `git clone https://github.com/caddyserver/caddy.git` in any folder (doesn't have to be in GOPATH).
|
||||||
|
|
||||||
|
You can make changes to the source code from that clone and checkout any commit or tag you wish to develop on.
|
||||||
|
|
||||||
|
When building from source, telemetry is enabled by default. You can disable it by changing `caddymain.EnableTelemetry = false` in run.go, or use the `-disabled-metrics` flag at runtime to disable only certain metrics.
|
||||||
|
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
To serve static files from the current working directory, run:
|
||||||
|
|
||||||
|
```
|
||||||
|
caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
Caddy's default port is 2015, so open your browser to [http://localhost:2015](http://localhost:2015).
|
||||||
|
|
||||||
|
### Go from 0 to HTTPS in 5 seconds
|
||||||
|
|
||||||
|
If the `caddy` binary has permission to bind to low ports and your domain name's DNS records point to the machine you're on:
|
||||||
|
|
||||||
|
```
|
||||||
|
caddy -host example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
This command serves static files from the current directory over HTTPS. Certificates are automatically obtained and renewed for you! Caddy is also automatically configuring ports 80 and 443 for you, and redirecting HTTP to HTTPS. Cool, huh?
|
||||||
|
|
||||||
|
### Customizing your site
|
||||||
|
|
||||||
|
To customize how your site is served, create a file named Caddyfile by your site and paste this into it:
|
||||||
|
|
||||||
|
```plain
|
||||||
|
localhost
|
||||||
|
|
||||||
|
push
|
||||||
|
browse
|
||||||
|
websocket /echo cat
|
||||||
|
ext .html
|
||||||
|
log /var/log/access.log
|
||||||
|
proxy /api 127.0.0.1:7005
|
||||||
|
header /api Access-Control-Allow-Origin *
|
||||||
|
```
|
||||||
|
|
||||||
|
When you run `caddy` in that directory, it will automatically find and use that Caddyfile.
|
||||||
|
|
||||||
|
This simple file enables server push (via Link headers), allows directory browsing (for folders without an index file), hosts a WebSocket echo server at /echo, serves clean URLs, logs requests to an access log, proxies all API requests to a backend on port 7005, and adds the coveted `Access-Control-Allow-Origin: *` header for all responses from the API.
|
||||||
|
|
||||||
|
Wow! Caddy can do a lot with just a few lines.
|
||||||
|
|
||||||
|
### Doing more with Caddy
|
||||||
|
|
||||||
|
To host multiple sites and do more with the Caddyfile, please see the [Caddyfile tutorial](https://caddyserver.com/tutorial/caddyfile).
|
||||||
|
|
||||||
|
Sites with qualifying hostnames are served over [HTTPS by default](https://caddyserver.com/docs/automatic-https).
|
||||||
|
|
||||||
|
Caddy has a nice little command line interface. Run `caddy -h` to view basic help or see the [CLI documentation](https://caddyserver.com/docs/cli) for details.
|
||||||
|
|
||||||
|
|
||||||
|
## Running in Production
|
||||||
|
|
||||||
|
Caddy is production-ready if you find it to be a good fit for your site and workflow.
|
||||||
|
|
||||||
|
**Running as root:** We advise against this. You can still listen on ports < 1024 on Linux using setcap like so: `sudo setcap cap_net_bind_service=+ep ./caddy`
|
||||||
|
|
||||||
|
The Caddy project does not officially maintain any system-specific integrations nor suggest how to administer your own system. But your download file includes [unofficial resources](https://github.com/caddyserver/caddy/tree/master/dist/init) contributed by the community that you may find helpful for running Caddy in production.
|
||||||
|
|
||||||
|
How you choose to run Caddy is up to you. Many users are satisfied with `nohup caddy &`. Others use `screen`. Users who need Caddy to come back up after reboots either do so in the script that caused the reboot, add a command to an init script, or configure a service with their OS.
|
||||||
|
|
||||||
|
If you have questions or concerns about Caddy' underlying crypto implementations, consult Go's [crypto packages](https://golang.org/pkg/crypto), starting with their documentation, then issues, then the code itself; as Caddy uses mainly those libraries.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
**[Join our forum](https://caddy.community) where you can chat with other Caddy users and developers!** To get familiar with the code base, try [Caddy code search on Sourcegraph](https://sourcegraph.com/github.com/caddyserver/caddy/)!
|
||||||
|
|
||||||
|
Please see our [contributing guidelines](https://github.com/caddyserver/caddy/blob/master/.github/CONTRIBUTING.md) for instructions. If you want to write a plugin, check out the [developer wiki](https://github.com/caddyserver/caddy/wiki).
|
||||||
|
|
||||||
|
We use GitHub issues and pull requests only for discussing bug reports and the development of specific changes. We welcome all other topics on the [forum](https://caddy.community)!
|
||||||
|
|
||||||
|
If you want to contribute to the documentation, please [submit an issue](https://github.com/caddyserver/caddy/issues/new) describing the change that should be made.
|
||||||
|
|
||||||
|
### Good First Issue
|
||||||
|
|
||||||
|
If you are looking for somewhere to start and would like to help out by working on an existing issue, take a look at our [`Good First Issue`](https://github.com/caddyserver/caddy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tag
|
||||||
|
|
||||||
|
Thanks for making Caddy -- and the Web -- better!
|
||||||
|
|
||||||
|
|
||||||
|
## Donors
|
||||||
|
|
||||||
|
- [DigitalOcean](https://m.do.co/c/6d7bdafccf96) is hosting the Caddy project.
|
||||||
|
- [DNSimple](https://dnsimple.link/resolving-caddy) provides DNS services for Caddy's sites.
|
||||||
|
- [DNS Spy](https://dnsspy.io) keeps an eye on Caddy's DNS properties.
|
||||||
|
|
||||||
|
We thank them for their services. **If you want to help keep Caddy free, please [become a sponsor](https://github.com/sponsors/mholt)!**
|
||||||
|
|
||||||
|
|
||||||
|
## About the Project
|
||||||
|
|
||||||
|
Caddy was born out of the need for a "batteries-included" web server that runs anywhere and doesn't have to take its configuration with it. Caddy took inspiration from [spark](https://github.com/rif/spark), [nginx](https://github.com/nginx/nginx), lighttpd,
|
||||||
|
[Websocketd](https://github.com/joewalnes/websocketd) and [Vagrant](https://www.vagrantup.com/), which provides a pleasant mixture of features from each of them.
|
||||||
|
|
||||||
|
**The name "Caddy" is trademarked:** The name of the software is "Caddy", not "Caddy Server" or "CaddyServer". Please call it "Caddy" or, if you wish to clarify, "the Caddy web server". See [brand guidelines](https://caddyserver.com/brand). Caddy is a registered trademark of Light Code Labs, LLC.
|
||||||
|
|
||||||
|
*Author on Twitter: [@mholt6](https://twitter.com/mholt6)*
|
48
vendor/github.com/caddyserver/caddy/assets.go
generated
vendored
Normal file
48
vendor/github.com/caddyserver/caddy/assets.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AssetsPath returns the path to the folder
|
||||||
|
// where the application may store data. If
|
||||||
|
// CADDYPATH env variable is set, that value
|
||||||
|
// is used. Otherwise, the path is the result
|
||||||
|
// of evaluating "$HOME/.caddy".
|
||||||
|
func AssetsPath() string {
|
||||||
|
if caddyPath := os.Getenv("CADDYPATH"); caddyPath != "" {
|
||||||
|
return caddyPath
|
||||||
|
}
|
||||||
|
return filepath.Join(userHomeDir(), ".caddy")
|
||||||
|
}
|
||||||
|
|
||||||
|
// userHomeDir returns the user's home directory according to
|
||||||
|
// environment variables.
|
||||||
|
//
|
||||||
|
// Credit: http://stackoverflow.com/a/7922977/1048862
|
||||||
|
func userHomeDir() string {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||||
|
if home == "" {
|
||||||
|
home = os.Getenv("USERPROFILE")
|
||||||
|
}
|
||||||
|
return home
|
||||||
|
}
|
||||||
|
return os.Getenv("HOME")
|
||||||
|
}
|
88
vendor/github.com/caddyserver/caddy/azure-pipelines.yml
generated
vendored
Normal file
88
vendor/github.com/caddyserver/caddy/azure-pipelines.yml
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# Mutilated beyond recognition from the example at:
|
||||||
|
# https://docs.microsoft.com/azure/devops/pipelines/languages/go
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
- master
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
linux:
|
||||||
|
imageName: ubuntu-16.04
|
||||||
|
gorootDir: /usr/local
|
||||||
|
mac:
|
||||||
|
imageName: macos-10.13
|
||||||
|
gorootDir: /usr/local
|
||||||
|
windows:
|
||||||
|
imageName: windows-2019
|
||||||
|
gorootDir: C:\
|
||||||
|
|
||||||
|
pool:
|
||||||
|
vmImage: $(imageName)
|
||||||
|
|
||||||
|
variables:
|
||||||
|
GOROOT: $(gorootDir)/go
|
||||||
|
GOPATH: $(system.defaultWorkingDirectory)/gopath
|
||||||
|
GOBIN: $(GOPATH)/bin
|
||||||
|
modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)'
|
||||||
|
# TODO: modules should be the default in Go 1.13, so this won't be needed
|
||||||
|
GO111MODULE: on
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- bash: |
|
||||||
|
latestGo=$(curl "https://golang.org/VERSION?m=text")
|
||||||
|
echo "##vso[task.setvariable variable=LATEST_GO]$latestGo"
|
||||||
|
echo "Latest Go version: $latestGo"
|
||||||
|
displayName: "Get latest Go version"
|
||||||
|
|
||||||
|
- bash: |
|
||||||
|
sudo rm -f $(which go)
|
||||||
|
echo '##vso[task.prependpath]$(GOBIN)'
|
||||||
|
echo '##vso[task.prependpath]$(GOROOT)/bin'
|
||||||
|
mkdir -p '$(modulePath)'
|
||||||
|
shopt -s extglob
|
||||||
|
shopt -s dotglob
|
||||||
|
mv !(gopath) '$(modulePath)'
|
||||||
|
displayName: Remove old Go, set GOBIN/GOROOT, and move project into GOPATH
|
||||||
|
|
||||||
|
# Install Go (this varies by platform)
|
||||||
|
|
||||||
|
- bash: |
|
||||||
|
wget "https://dl.google.com/go/$(LATEST_GO).linux-amd64.tar.gz"
|
||||||
|
sudo tar -C $(gorootDir) -xzf "$(LATEST_GO).linux-amd64.tar.gz"
|
||||||
|
condition: eq( variables['Agent.OS'], 'Linux' )
|
||||||
|
displayName: Install Go on Linux
|
||||||
|
|
||||||
|
- bash: |
|
||||||
|
wget "https://dl.google.com/go/$(LATEST_GO).darwin-amd64.tar.gz"
|
||||||
|
sudo tar -C $(gorootDir) -xzf "$(LATEST_GO).darwin-amd64.tar.gz"
|
||||||
|
condition: eq( variables['Agent.OS'], 'Darwin' )
|
||||||
|
displayName: Install Go on macOS
|
||||||
|
|
||||||
|
- powershell: |
|
||||||
|
Write-Host "Downloading Go... (please be patient, I am very slow)"
|
||||||
|
(New-Object System.Net.WebClient).DownloadFile("https://dl.google.com/go/$(LATEST_GO).windows-amd64.zip", "$(LATEST_GO).windows-amd64.zip")
|
||||||
|
Write-Host "Extracting Go... (I'm slow too)"
|
||||||
|
Expand-Archive "$(LATEST_GO).windows-amd64.zip" -DestinationPath "$(gorootDir)"
|
||||||
|
condition: eq( variables['Agent.OS'], 'Windows_NT' )
|
||||||
|
displayName: Install Go on Windows
|
||||||
|
|
||||||
|
# TODO: When this issue is fixed, replace with installer script:
|
||||||
|
# https://github.com/golangci/golangci-lint/issues/472
|
||||||
|
- script: go get -v github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||||
|
displayName: Install golangci-lint
|
||||||
|
|
||||||
|
- bash: |
|
||||||
|
printf "Using go at: $(which go)\n"
|
||||||
|
printf "Go version: $(go version)\n"
|
||||||
|
printf "\n\nGo environment:\n\n"
|
||||||
|
go env
|
||||||
|
printf "\n\nSystem environment:\n\n"
|
||||||
|
env
|
||||||
|
displayName: Print Go version and environment
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
go get -v -t -d ./...
|
||||||
|
golangci-lint run -E gofmt -E goimports -E misspell
|
||||||
|
go test -race ./...
|
||||||
|
workingDirectory: '$(modulePath)'
|
||||||
|
displayName: Run tests
|
1036
vendor/github.com/caddyserver/caddy/caddy.go
generated
vendored
Normal file
1036
vendor/github.com/caddyserver/caddy/caddy.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
260
vendor/github.com/caddyserver/caddy/caddyfile/dispenser.go
generated
vendored
Normal file
260
vendor/github.com/caddyserver/caddy/caddyfile/dispenser.go
generated
vendored
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddyfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Dispenser is a type that dispenses tokens, similarly to a lexer,
|
||||||
|
// except that it can do so with some notion of structure and has
|
||||||
|
// some really convenient methods.
|
||||||
|
type Dispenser struct {
|
||||||
|
filename string
|
||||||
|
tokens []Token
|
||||||
|
cursor int
|
||||||
|
nesting int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDispenser returns a Dispenser, ready to use for parsing the given input.
|
||||||
|
func NewDispenser(filename string, input io.Reader) Dispenser {
|
||||||
|
tokens, _ := allTokens(input) // ignoring error because nothing to do with it
|
||||||
|
return Dispenser{
|
||||||
|
filename: filename,
|
||||||
|
tokens: tokens,
|
||||||
|
cursor: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDispenserTokens returns a Dispenser filled with the given tokens.
|
||||||
|
func NewDispenserTokens(filename string, tokens []Token) Dispenser {
|
||||||
|
return Dispenser{
|
||||||
|
filename: filename,
|
||||||
|
tokens: tokens,
|
||||||
|
cursor: -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next loads the next token. Returns true if a token
|
||||||
|
// was loaded; false otherwise. If false, all tokens
|
||||||
|
// have been consumed.
|
||||||
|
func (d *Dispenser) Next() bool {
|
||||||
|
if d.cursor < len(d.tokens)-1 {
|
||||||
|
d.cursor++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextArg loads the next token if it is on the same
|
||||||
|
// line. Returns true if a token was loaded; false
|
||||||
|
// otherwise. If false, all tokens on the line have
|
||||||
|
// been consumed. It handles imported tokens correctly.
|
||||||
|
func (d *Dispenser) NextArg() bool {
|
||||||
|
if d.cursor < 0 {
|
||||||
|
d.cursor++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if d.cursor >= len(d.tokens) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if d.cursor < len(d.tokens)-1 &&
|
||||||
|
d.tokens[d.cursor].File == d.tokens[d.cursor+1].File &&
|
||||||
|
d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) == d.tokens[d.cursor+1].Line {
|
||||||
|
d.cursor++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextLine loads the next token only if it is not on the same
|
||||||
|
// line as the current token, and returns true if a token was
|
||||||
|
// loaded; false otherwise. If false, there is not another token
|
||||||
|
// or it is on the same line. It handles imported tokens correctly.
|
||||||
|
func (d *Dispenser) NextLine() bool {
|
||||||
|
if d.cursor < 0 {
|
||||||
|
d.cursor++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if d.cursor >= len(d.tokens) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if d.cursor < len(d.tokens)-1 &&
|
||||||
|
(d.tokens[d.cursor].File != d.tokens[d.cursor+1].File ||
|
||||||
|
d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) < d.tokens[d.cursor+1].Line) {
|
||||||
|
d.cursor++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NextBlock can be used as the condition of a for loop
|
||||||
|
// to load the next token as long as it opens a block or
|
||||||
|
// is already in a block. It returns true if a token was
|
||||||
|
// loaded, or false when the block's closing curly brace
|
||||||
|
// was loaded and thus the block ended. Nested blocks are
|
||||||
|
// not supported.
|
||||||
|
func (d *Dispenser) NextBlock() bool {
|
||||||
|
if d.nesting > 0 {
|
||||||
|
d.Next()
|
||||||
|
if d.Val() == "}" {
|
||||||
|
d.nesting--
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !d.NextArg() { // block must open on same line
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if d.Val() != "{" {
|
||||||
|
d.cursor-- // roll back if not opening brace
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
d.Next()
|
||||||
|
if d.Val() == "}" {
|
||||||
|
// Open and then closed right away
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
d.nesting++
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Val gets the text of the current token. If there is no token
|
||||||
|
// loaded, it returns empty string.
|
||||||
|
func (d *Dispenser) Val() string {
|
||||||
|
if d.cursor < 0 || d.cursor >= len(d.tokens) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return d.tokens[d.cursor].Text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line gets the line number of the current token. If there is no token
|
||||||
|
// loaded, it returns 0.
|
||||||
|
func (d *Dispenser) Line() int {
|
||||||
|
if d.cursor < 0 || d.cursor >= len(d.tokens) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return d.tokens[d.cursor].Line
|
||||||
|
}
|
||||||
|
|
||||||
|
// File gets the filename of the current token. If there is no token loaded,
|
||||||
|
// it returns the filename originally given when parsing started.
|
||||||
|
func (d *Dispenser) File() string {
|
||||||
|
if d.cursor < 0 || d.cursor >= len(d.tokens) {
|
||||||
|
return d.filename
|
||||||
|
}
|
||||||
|
if tokenFilename := d.tokens[d.cursor].File; tokenFilename != "" {
|
||||||
|
return tokenFilename
|
||||||
|
}
|
||||||
|
return d.filename
|
||||||
|
}
|
||||||
|
|
||||||
|
// Args is a convenience function that loads the next arguments
|
||||||
|
// (tokens on the same line) into an arbitrary number of strings
|
||||||
|
// pointed to in targets. If there are fewer tokens available
|
||||||
|
// than string pointers, the remaining strings will not be changed
|
||||||
|
// and false will be returned. If there were enough tokens available
|
||||||
|
// to fill the arguments, then true will be returned.
|
||||||
|
func (d *Dispenser) Args(targets ...*string) bool {
|
||||||
|
enough := true
|
||||||
|
for i := 0; i < len(targets); i++ {
|
||||||
|
if !d.NextArg() {
|
||||||
|
enough = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
*targets[i] = d.Val()
|
||||||
|
}
|
||||||
|
return enough
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemainingArgs loads any more arguments (tokens on the same line)
|
||||||
|
// into a slice and returns them. Open curly brace tokens also indicate
|
||||||
|
// the end of arguments, and the curly brace is not included in
|
||||||
|
// the return value nor is it loaded.
|
||||||
|
func (d *Dispenser) RemainingArgs() []string {
|
||||||
|
var args []string
|
||||||
|
|
||||||
|
for d.NextArg() {
|
||||||
|
if d.Val() == "{" {
|
||||||
|
d.cursor--
|
||||||
|
break
|
||||||
|
}
|
||||||
|
args = append(args, d.Val())
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArgErr returns an argument error, meaning that another
|
||||||
|
// argument was expected but not found. In other words,
|
||||||
|
// a line break or open curly brace was encountered instead of
|
||||||
|
// an argument.
|
||||||
|
func (d *Dispenser) ArgErr() error {
|
||||||
|
if d.Val() == "{" {
|
||||||
|
return d.Err("Unexpected token '{', expecting argument")
|
||||||
|
}
|
||||||
|
return d.Errf("Wrong argument count or unexpected line ending after '%s'", d.Val())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyntaxErr creates a generic syntax error which explains what was
|
||||||
|
// found and what was expected.
|
||||||
|
func (d *Dispenser) SyntaxErr(expected string) error {
|
||||||
|
msg := fmt.Sprintf("%s:%d - Syntax error: Unexpected token '%s', expecting '%s'", d.File(), d.Line(), d.Val(), expected)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOFErr returns an error indicating that the dispenser reached
|
||||||
|
// the end of the input when searching for the next token.
|
||||||
|
func (d *Dispenser) EOFErr() error {
|
||||||
|
return d.Errf("Unexpected EOF")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err generates a custom parse-time error with a message of msg.
|
||||||
|
func (d *Dispenser) Err(msg string) error {
|
||||||
|
msg = fmt.Sprintf("%s:%d - Error during parsing: %s", d.File(), d.Line(), msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errf is like Err, but for formatted error messages
|
||||||
|
func (d *Dispenser) Errf(format string, args ...interface{}) error {
|
||||||
|
return d.Err(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// numLineBreaks counts how many line breaks are in the token
|
||||||
|
// value given by the token index tknIdx. It returns 0 if the
|
||||||
|
// token does not exist or there are no line breaks.
|
||||||
|
func (d *Dispenser) numLineBreaks(tknIdx int) int {
|
||||||
|
if tknIdx < 0 || tknIdx >= len(d.tokens) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return strings.Count(d.tokens[tknIdx].Text, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// isNewLine determines whether the current token is on a different
|
||||||
|
// line (higher line number) than the previous token. It handles imported
|
||||||
|
// tokens correctly. If there isn't a previous token, it returns true.
|
||||||
|
func (d *Dispenser) isNewLine() bool {
|
||||||
|
if d.cursor < 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if d.cursor > len(d.tokens)-1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return d.tokens[d.cursor-1].File != d.tokens[d.cursor].File ||
|
||||||
|
d.tokens[d.cursor-1].Line+d.numLineBreaks(d.cursor-1) < d.tokens[d.cursor].Line
|
||||||
|
}
|
198
vendor/github.com/caddyserver/caddy/caddyfile/json.go
generated
vendored
Normal file
198
vendor/github.com/caddyserver/caddy/caddyfile/json.go
generated
vendored
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddyfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const filename = "Caddyfile"
|
||||||
|
|
||||||
|
// ToJSON converts caddyfile to its JSON representation.
|
||||||
|
func ToJSON(caddyfile []byte) ([]byte, error) {
|
||||||
|
var j EncodedCaddyfile
|
||||||
|
|
||||||
|
serverBlocks, err := Parse(filename, bytes.NewReader(caddyfile), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sb := range serverBlocks {
|
||||||
|
block := EncodedServerBlock{
|
||||||
|
Keys: sb.Keys,
|
||||||
|
Body: [][]interface{}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract directives deterministically by sorting them
|
||||||
|
var directives = make([]string, len(sb.Tokens))
|
||||||
|
for dir := range sb.Tokens {
|
||||||
|
directives = append(directives, dir)
|
||||||
|
}
|
||||||
|
sort.Strings(directives)
|
||||||
|
|
||||||
|
// Convert each directive's tokens into our JSON structure
|
||||||
|
for _, dir := range directives {
|
||||||
|
disp := NewDispenserTokens(filename, sb.Tokens[dir])
|
||||||
|
for disp.Next() {
|
||||||
|
block.Body = append(block.Body, constructLine(&disp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tack this block onto the end of the list
|
||||||
|
j = append(j, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := json.Marshal(j)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructLine transforms tokens into a JSON-encodable structure;
|
||||||
|
// but only one line at a time, to be used at the top-level of
|
||||||
|
// a server block only (where the first token on each line is a
|
||||||
|
// directive) - not to be used at any other nesting level.
|
||||||
|
func constructLine(d *Dispenser) []interface{} {
|
||||||
|
var args []interface{}
|
||||||
|
|
||||||
|
args = append(args, d.Val())
|
||||||
|
|
||||||
|
for d.NextArg() {
|
||||||
|
if d.Val() == "{" {
|
||||||
|
args = append(args, constructBlock(d))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
args = append(args, d.Val())
|
||||||
|
}
|
||||||
|
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructBlock recursively processes tokens into a
|
||||||
|
// JSON-encodable structure. To be used in a directive's
|
||||||
|
// block. Goes to end of block.
|
||||||
|
func constructBlock(d *Dispenser) [][]interface{} {
|
||||||
|
block := [][]interface{}{}
|
||||||
|
|
||||||
|
for d.Next() {
|
||||||
|
if d.Val() == "}" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
block = append(block, constructLine(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromJSON converts JSON-encoded jsonBytes to Caddyfile text
|
||||||
|
func FromJSON(jsonBytes []byte) ([]byte, error) {
|
||||||
|
var j EncodedCaddyfile
|
||||||
|
var result string
|
||||||
|
|
||||||
|
err := json.Unmarshal(jsonBytes, &j)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for sbPos, sb := range j {
|
||||||
|
if sbPos > 0 {
|
||||||
|
result += "\n\n"
|
||||||
|
}
|
||||||
|
for i, key := range sb.Keys {
|
||||||
|
if i > 0 {
|
||||||
|
result += ", "
|
||||||
|
}
|
||||||
|
//result += standardizeScheme(key)
|
||||||
|
result += key
|
||||||
|
}
|
||||||
|
result += jsonToText(sb.Body, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte(result), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonToText recursively transforms a scope of JSON into plain
|
||||||
|
// Caddyfile text.
|
||||||
|
func jsonToText(scope interface{}, depth int) string {
|
||||||
|
var result string
|
||||||
|
|
||||||
|
switch val := scope.(type) {
|
||||||
|
case string:
|
||||||
|
if strings.ContainsAny(val, "\" \n\t\r") {
|
||||||
|
result += `"` + strings.Replace(val, "\"", "\\\"", -1) + `"`
|
||||||
|
} else {
|
||||||
|
result += val
|
||||||
|
}
|
||||||
|
case int:
|
||||||
|
result += strconv.Itoa(val)
|
||||||
|
case float64:
|
||||||
|
result += fmt.Sprintf("%v", val)
|
||||||
|
case bool:
|
||||||
|
result += fmt.Sprintf("%t", val)
|
||||||
|
case [][]interface{}:
|
||||||
|
result += " {\n"
|
||||||
|
for _, arg := range val {
|
||||||
|
result += strings.Repeat("\t", depth) + jsonToText(arg, depth+1) + "\n"
|
||||||
|
}
|
||||||
|
result += strings.Repeat("\t", depth-1) + "}"
|
||||||
|
case []interface{}:
|
||||||
|
for i, v := range val {
|
||||||
|
if block, ok := v.([]interface{}); ok {
|
||||||
|
result += "{\n"
|
||||||
|
for _, arg := range block {
|
||||||
|
result += strings.Repeat("\t", depth) + jsonToText(arg, depth+1) + "\n"
|
||||||
|
}
|
||||||
|
result += strings.Repeat("\t", depth-1) + "}"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result += jsonToText(v, depth)
|
||||||
|
if i < len(val)-1 {
|
||||||
|
result += " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Will this function come in handy somewhere else?
|
||||||
|
/*
|
||||||
|
// standardizeScheme turns an address like host:https into https://host,
|
||||||
|
// or "host:" into "host".
|
||||||
|
func standardizeScheme(addr string) string {
|
||||||
|
if hostname, port, err := net.SplitHostPort(addr); err == nil {
|
||||||
|
if port == "http" || port == "https" {
|
||||||
|
addr = port + "://" + hostname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.TrimSuffix(addr, ":")
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// EncodedCaddyfile encapsulates a slice of EncodedServerBlocks.
|
||||||
|
type EncodedCaddyfile []EncodedServerBlock
|
||||||
|
|
||||||
|
// EncodedServerBlock represents a server block ripe for encoding.
|
||||||
|
type EncodedServerBlock struct {
|
||||||
|
Keys []string `json:"keys"`
|
||||||
|
Body [][]interface{} `json:"body"`
|
||||||
|
}
|
150
vendor/github.com/caddyserver/caddy/caddyfile/lexer.go
generated
vendored
Normal file
150
vendor/github.com/caddyserver/caddy/caddyfile/lexer.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddyfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// lexer is a utility which can get values, token by
|
||||||
|
// token, from a Reader. A token is a word, and tokens
|
||||||
|
// are separated by whitespace. A word can be enclosed
|
||||||
|
// in quotes if it contains whitespace.
|
||||||
|
lexer struct {
|
||||||
|
reader *bufio.Reader
|
||||||
|
token Token
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token represents a single parsable unit.
|
||||||
|
Token struct {
|
||||||
|
File string
|
||||||
|
Line int
|
||||||
|
Text string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// load prepares the lexer to scan an input for tokens.
|
||||||
|
// It discards any leading byte order mark.
|
||||||
|
func (l *lexer) load(input io.Reader) error {
|
||||||
|
l.reader = bufio.NewReader(input)
|
||||||
|
l.line = 1
|
||||||
|
|
||||||
|
// discard byte order mark, if present
|
||||||
|
firstCh, _, err := l.reader.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if firstCh != 0xFEFF {
|
||||||
|
err := l.reader.UnreadRune()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// next loads the next token into the lexer.
|
||||||
|
// A token is delimited by whitespace, unless
|
||||||
|
// the token starts with a quotes character (")
|
||||||
|
// in which case the token goes until the closing
|
||||||
|
// quotes (the enclosing quotes are not included).
|
||||||
|
// Inside quoted strings, quotes may be escaped
|
||||||
|
// with a preceding \ character. No other chars
|
||||||
|
// may be escaped. The rest of the line is skipped
|
||||||
|
// if a "#" character is read in. Returns true if
|
||||||
|
// a token was loaded; false otherwise.
|
||||||
|
func (l *lexer) next() bool {
|
||||||
|
var val []rune
|
||||||
|
var comment, quoted, escaped bool
|
||||||
|
|
||||||
|
makeToken := func() bool {
|
||||||
|
l.token.Text = string(val)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
ch, _, err := l.reader.ReadRune()
|
||||||
|
if err != nil {
|
||||||
|
if len(val) > 0 {
|
||||||
|
return makeToken()
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if quoted {
|
||||||
|
if !escaped {
|
||||||
|
if ch == '\\' {
|
||||||
|
escaped = true
|
||||||
|
continue
|
||||||
|
} else if ch == '"' {
|
||||||
|
quoted = false
|
||||||
|
return makeToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ch == '\n' {
|
||||||
|
l.line++
|
||||||
|
}
|
||||||
|
if escaped {
|
||||||
|
// only escape quotes
|
||||||
|
if ch != '"' {
|
||||||
|
val = append(val, '\\')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val = append(val, ch)
|
||||||
|
escaped = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if unicode.IsSpace(ch) {
|
||||||
|
if ch == '\r' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ch == '\n' {
|
||||||
|
l.line++
|
||||||
|
comment = false
|
||||||
|
}
|
||||||
|
if len(val) > 0 {
|
||||||
|
return makeToken()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == '#' {
|
||||||
|
comment = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(val) == 0 {
|
||||||
|
l.token = Token{Line: l.line}
|
||||||
|
if ch == '"' {
|
||||||
|
quoted = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val = append(val, ch)
|
||||||
|
}
|
||||||
|
}
|
490
vendor/github.com/caddyserver/caddy/caddyfile/parse.go
generated
vendored
Normal file
490
vendor/github.com/caddyserver/caddy/caddyfile/parse.go
generated
vendored
Normal file
@ -0,0 +1,490 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddyfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse parses the input just enough to group tokens, in
|
||||||
|
// order, by server block. No further parsing is performed.
|
||||||
|
// Server blocks are returned in the order in which they appear.
|
||||||
|
// Directives that do not appear in validDirectives will cause
|
||||||
|
// an error. If you do not want to check for valid directives,
|
||||||
|
// pass in nil instead.
|
||||||
|
func Parse(filename string, input io.Reader, validDirectives []string) ([]ServerBlock, error) {
|
||||||
|
p := parser{Dispenser: NewDispenser(filename, input), validDirectives: validDirectives}
|
||||||
|
return p.parseAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
// allTokens lexes the entire input, but does not parse it.
|
||||||
|
// It returns all the tokens from the input, unstructured
|
||||||
|
// and in order.
|
||||||
|
func allTokens(input io.Reader) ([]Token, error) {
|
||||||
|
l := new(lexer)
|
||||||
|
err := l.load(input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var tokens []Token
|
||||||
|
for l.next() {
|
||||||
|
tokens = append(tokens, l.token)
|
||||||
|
}
|
||||||
|
return tokens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type parser struct {
|
||||||
|
Dispenser
|
||||||
|
block ServerBlock // current server block being parsed
|
||||||
|
validDirectives []string // a directive must be valid or it's an error
|
||||||
|
eof bool // if we encounter a valid EOF in a hard place
|
||||||
|
definedSnippets map[string][]Token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) parseAll() ([]ServerBlock, error) {
|
||||||
|
var blocks []ServerBlock
|
||||||
|
|
||||||
|
for p.Next() {
|
||||||
|
err := p.parseOne()
|
||||||
|
if err != nil {
|
||||||
|
return blocks, err
|
||||||
|
}
|
||||||
|
if len(p.block.Keys) > 0 {
|
||||||
|
blocks = append(blocks, p.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) parseOne() error {
|
||||||
|
p.block = ServerBlock{Tokens: make(map[string][]Token)}
|
||||||
|
|
||||||
|
return p.begin()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) begin() error {
|
||||||
|
if len(p.tokens) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.addresses()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.eof {
|
||||||
|
// this happens if the Caddyfile consists of only
|
||||||
|
// a line of addresses and nothing else
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok, name := p.isSnippet(); ok {
|
||||||
|
if p.definedSnippets == nil {
|
||||||
|
p.definedSnippets = map[string][]Token{}
|
||||||
|
}
|
||||||
|
if _, found := p.definedSnippets[name]; found {
|
||||||
|
return p.Errf("redeclaration of previously declared snippet %s", name)
|
||||||
|
}
|
||||||
|
// consume all tokens til matched close brace
|
||||||
|
tokens, err := p.snippetTokens()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.definedSnippets[name] = tokens
|
||||||
|
// empty block keys so we don't save this block as a real server.
|
||||||
|
p.block.Keys = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.blockContents()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) addresses() error {
|
||||||
|
var expectingAnother bool
|
||||||
|
|
||||||
|
for {
|
||||||
|
tkn := replaceEnvVars(p.Val())
|
||||||
|
|
||||||
|
// special case: import directive replaces tokens during parse-time
|
||||||
|
if tkn == "import" && p.isNewLine() {
|
||||||
|
err := p.doImport()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open brace definitely indicates end of addresses
|
||||||
|
if tkn == "{" {
|
||||||
|
if expectingAnother {
|
||||||
|
return p.Errf("Expected another address but had '%s' - check for extra comma", tkn)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if tkn != "" { // empty token possible if user typed ""
|
||||||
|
// Trailing comma indicates another address will follow, which
|
||||||
|
// may possibly be on the next line
|
||||||
|
if tkn[len(tkn)-1] == ',' {
|
||||||
|
tkn = tkn[:len(tkn)-1]
|
||||||
|
expectingAnother = true
|
||||||
|
} else {
|
||||||
|
expectingAnother = false // but we may still see another one on this line
|
||||||
|
}
|
||||||
|
|
||||||
|
p.block.Keys = append(p.block.Keys, tkn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance token and possibly break out of loop or return error
|
||||||
|
hasNext := p.Next()
|
||||||
|
if expectingAnother && !hasNext {
|
||||||
|
return p.EOFErr()
|
||||||
|
}
|
||||||
|
if !hasNext {
|
||||||
|
p.eof = true
|
||||||
|
break // EOF
|
||||||
|
}
|
||||||
|
if !expectingAnother && p.isNewLine() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) blockContents() error {
|
||||||
|
errOpenCurlyBrace := p.openCurlyBrace()
|
||||||
|
if errOpenCurlyBrace != nil {
|
||||||
|
// single-server configs don't need curly braces
|
||||||
|
p.cursor--
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.directives()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only look for close curly brace if there was an opening
|
||||||
|
if errOpenCurlyBrace == nil {
|
||||||
|
err = p.closeCurlyBrace()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// directives parses through all the lines for directives
|
||||||
|
// and it expects the next token to be the first
|
||||||
|
// directive. It goes until EOF or closing curly brace
|
||||||
|
// which ends the server block.
|
||||||
|
func (p *parser) directives() error {
|
||||||
|
for p.Next() {
|
||||||
|
// end of server block
|
||||||
|
if p.Val() == "}" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case: import directive replaces tokens during parse-time
|
||||||
|
if p.Val() == "import" {
|
||||||
|
err := p.doImport()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.cursor-- // cursor is advanced when we continue, so roll back one more
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal case: parse a directive on this line
|
||||||
|
if err := p.directive(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// doImport swaps out the import directive and its argument
|
||||||
|
// (a total of 2 tokens) with the tokens in the specified file
|
||||||
|
// or globbing pattern. When the function returns, the cursor
|
||||||
|
// is on the token before where the import directive was. In
|
||||||
|
// other words, call Next() to access the first token that was
|
||||||
|
// imported.
|
||||||
|
func (p *parser) doImport() error {
|
||||||
|
// syntax checks
|
||||||
|
if !p.NextArg() {
|
||||||
|
return p.ArgErr()
|
||||||
|
}
|
||||||
|
importPattern := replaceEnvVars(p.Val())
|
||||||
|
if importPattern == "" {
|
||||||
|
return p.Err("Import requires a non-empty filepath")
|
||||||
|
}
|
||||||
|
if p.NextArg() {
|
||||||
|
return p.Err("Import takes only one argument (glob pattern or file)")
|
||||||
|
}
|
||||||
|
// splice out the import directive and its argument (2 tokens total)
|
||||||
|
tokensBefore := p.tokens[:p.cursor-1]
|
||||||
|
tokensAfter := p.tokens[p.cursor+1:]
|
||||||
|
var importedTokens []Token
|
||||||
|
|
||||||
|
// first check snippets. That is a simple, non-recursive replacement
|
||||||
|
if p.definedSnippets != nil && p.definedSnippets[importPattern] != nil {
|
||||||
|
importedTokens = p.definedSnippets[importPattern]
|
||||||
|
} else {
|
||||||
|
// make path relative to the file of the _token_ being processed rather
|
||||||
|
// than current working directory (issue #867) and then use glob to get
|
||||||
|
// list of matching filenames
|
||||||
|
absFile, err := filepath.Abs(p.Dispenser.File())
|
||||||
|
if err != nil {
|
||||||
|
return p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var matches []string
|
||||||
|
var globPattern string
|
||||||
|
if !filepath.IsAbs(importPattern) {
|
||||||
|
globPattern = filepath.Join(filepath.Dir(absFile), importPattern)
|
||||||
|
} else {
|
||||||
|
globPattern = importPattern
|
||||||
|
}
|
||||||
|
if strings.Count(globPattern, "*") > 1 || strings.Count(globPattern, "?") > 1 ||
|
||||||
|
(strings.Contains(globPattern, "[") && strings.Contains(globPattern, "]")) {
|
||||||
|
// See issue #2096 - a pattern with many glob expansions can hang for too long
|
||||||
|
return p.Errf("Glob pattern may only contain one wildcard (*), but has others: %s", globPattern)
|
||||||
|
}
|
||||||
|
matches, err = filepath.Glob(globPattern)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return p.Errf("Failed to use import pattern %s: %v", importPattern, err)
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
if strings.ContainsAny(globPattern, "*?[]") {
|
||||||
|
log.Printf("[WARNING] No files matching import glob pattern: %s", importPattern)
|
||||||
|
} else {
|
||||||
|
return p.Errf("File to import not found: %s", importPattern)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all the imported tokens
|
||||||
|
|
||||||
|
for _, importFile := range matches {
|
||||||
|
newTokens, err := p.doSingleImport(importFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
importedTokens = append(importedTokens, newTokens...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// splice the imported tokens in the place of the import statement
|
||||||
|
// and rewind cursor so Next() will land on first imported token
|
||||||
|
p.tokens = append(tokensBefore, append(importedTokens, tokensAfter...)...)
|
||||||
|
p.cursor--
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// doSingleImport lexes the individual file at importFile and returns
|
||||||
|
// its tokens or an error, if any.
|
||||||
|
func (p *parser) doSingleImport(importFile string) ([]Token, error) {
|
||||||
|
file, err := os.Open(importFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, p.Errf("Could not import %s: %v", importFile, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if info, err := file.Stat(); err != nil {
|
||||||
|
return nil, p.Errf("Could not import %s: %v", importFile, err)
|
||||||
|
} else if info.IsDir() {
|
||||||
|
return nil, p.Errf("Could not import %s: is a directory", importFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
importedTokens, err := allTokens(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, p.Errf("Could not read tokens while importing %s: %v", importFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tack the file path onto these tokens so errors show the imported file's name
|
||||||
|
// (we use full, absolute path to avoid bugs: issue #1892)
|
||||||
|
filename, err := filepath.Abs(importFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, p.Errf("Failed to get absolute path of file: %s: %v", p.Dispenser.filename, err)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(importedTokens); i++ {
|
||||||
|
importedTokens[i].File = filename
|
||||||
|
}
|
||||||
|
|
||||||
|
return importedTokens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// directive collects tokens until the directive's scope
|
||||||
|
// closes (either end of line or end of curly brace block).
|
||||||
|
// It expects the currently-loaded token to be a directive
|
||||||
|
// (or } that ends a server block). The collected tokens
|
||||||
|
// are loaded into the current server block for later use
|
||||||
|
// by directive setup functions.
|
||||||
|
func (p *parser) directive() error {
|
||||||
|
dir := replaceEnvVars(p.Val())
|
||||||
|
nesting := 0
|
||||||
|
|
||||||
|
// TODO: More helpful error message ("did you mean..." or "maybe you need to install its server type")
|
||||||
|
if !p.validDirective(dir) {
|
||||||
|
return p.Errf("Unknown directive '%s'", dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The directive itself is appended as a relevant token
|
||||||
|
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
||||||
|
|
||||||
|
for p.Next() {
|
||||||
|
if p.Val() == "{" {
|
||||||
|
nesting++
|
||||||
|
} else if p.isNewLine() && nesting == 0 {
|
||||||
|
p.cursor-- // read too far
|
||||||
|
break
|
||||||
|
} else if p.Val() == "}" && nesting > 0 {
|
||||||
|
nesting--
|
||||||
|
} else if p.Val() == "}" && nesting == 0 {
|
||||||
|
return p.Err("Unexpected '}' because no matching opening brace")
|
||||||
|
} else if p.Val() == "import" && p.isNewLine() {
|
||||||
|
if err := p.doImport(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.cursor-- // cursor is advanced when we continue, so roll back one more
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.tokens[p.cursor].Text = replaceEnvVars(p.tokens[p.cursor].Text)
|
||||||
|
p.block.Tokens[dir] = append(p.block.Tokens[dir], p.tokens[p.cursor])
|
||||||
|
}
|
||||||
|
|
||||||
|
if nesting > 0 {
|
||||||
|
return p.EOFErr()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// openCurlyBrace expects the current token to be an
|
||||||
|
// opening curly brace. This acts like an assertion
|
||||||
|
// because it returns an error if the token is not
|
||||||
|
// a opening curly brace. It does NOT advance the token.
|
||||||
|
func (p *parser) openCurlyBrace() error {
|
||||||
|
if p.Val() != "{" {
|
||||||
|
return p.SyntaxErr("{")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// closeCurlyBrace expects the current token to be
|
||||||
|
// a closing curly brace. This acts like an assertion
|
||||||
|
// because it returns an error if the token is not
|
||||||
|
// a closing curly brace. It does NOT advance the token.
|
||||||
|
func (p *parser) closeCurlyBrace() error {
|
||||||
|
if p.Val() != "}" {
|
||||||
|
return p.SyntaxErr("}")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validDirective returns true if dir is in p.validDirectives.
|
||||||
|
func (p *parser) validDirective(dir string) bool {
|
||||||
|
if p.validDirectives == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, d := range p.validDirectives {
|
||||||
|
if d == dir {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaceEnvVars replaces environment variables that appear in the token
|
||||||
|
// and understands both the $UNIX and %WINDOWS% syntaxes.
|
||||||
|
func replaceEnvVars(s string) string {
|
||||||
|
s = replaceEnvReferences(s, "{%", "%}")
|
||||||
|
s = replaceEnvReferences(s, "{$", "}")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// replaceEnvReferences performs the actual replacement of env variables
|
||||||
|
// in s, given the placeholder start and placeholder end strings.
|
||||||
|
func replaceEnvReferences(s, refStart, refEnd string) string {
|
||||||
|
index := strings.Index(s, refStart)
|
||||||
|
for index != -1 {
|
||||||
|
endIndex := strings.Index(s[index:], refEnd)
|
||||||
|
if endIndex == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
endIndex += index
|
||||||
|
if endIndex > index+len(refStart) {
|
||||||
|
ref := s[index : endIndex+len(refEnd)]
|
||||||
|
s = strings.Replace(s, ref, os.Getenv(ref[len(refStart):len(ref)-len(refEnd)]), -1)
|
||||||
|
} else {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
index = strings.Index(s, refStart)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerBlock associates any number of keys (usually addresses
|
||||||
|
// of some sort) with tokens (grouped by directive name).
|
||||||
|
type ServerBlock struct {
|
||||||
|
Keys []string
|
||||||
|
Tokens map[string][]Token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) isSnippet() (bool, string) {
|
||||||
|
keys := p.block.Keys
|
||||||
|
// A snippet block is a single key with parens. Nothing else qualifies.
|
||||||
|
if len(keys) == 1 && strings.HasPrefix(keys[0], "(") && strings.HasSuffix(keys[0], ")") {
|
||||||
|
return true, strings.TrimSuffix(keys[0][1:], ")")
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// read and store everything in a block for later replay.
|
||||||
|
func (p *parser) snippetTokens() ([]Token, error) {
|
||||||
|
// TODO: disallow imports in snippets for simplicity at import time
|
||||||
|
// snippet must have curlies.
|
||||||
|
err := p.openCurlyBrace()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
count := 1
|
||||||
|
tokens := []Token{}
|
||||||
|
for p.Next() {
|
||||||
|
if p.Val() == "}" {
|
||||||
|
count--
|
||||||
|
if count == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.Val() == "{" {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
tokens = append(tokens, p.tokens[p.cursor])
|
||||||
|
}
|
||||||
|
// make sure we're matched up
|
||||||
|
if count != 0 {
|
||||||
|
return nil, p.SyntaxErr("}")
|
||||||
|
}
|
||||||
|
return tokens, nil
|
||||||
|
}
|
133
vendor/github.com/caddyserver/caddy/commands.go
generated
vendored
Normal file
133
vendor/github.com/caddyserver/caddy/commands.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"runtime"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/flynn/go-shlex"
|
||||||
|
)
|
||||||
|
|
||||||
|
var runtimeGoos = runtime.GOOS
|
||||||
|
|
||||||
|
// SplitCommandAndArgs takes a command string and parses it shell-style into the
|
||||||
|
// command and its separate arguments.
|
||||||
|
func SplitCommandAndArgs(command string) (cmd string, args []string, err error) {
|
||||||
|
var parts []string
|
||||||
|
|
||||||
|
if runtimeGoos == "windows" {
|
||||||
|
parts = parseWindowsCommand(command) // parse it Windows-style
|
||||||
|
} else {
|
||||||
|
parts, err = parseUnixCommand(command) // parse it Unix-style
|
||||||
|
if err != nil {
|
||||||
|
err = errors.New("error parsing command: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(parts) == 0 {
|
||||||
|
err = errors.New("no command contained in '" + command + "'")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = parts[0]
|
||||||
|
if len(parts) > 1 {
|
||||||
|
args = parts[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseUnixCommand parses a unix style command line and returns the
|
||||||
|
// command and its arguments or an error
|
||||||
|
func parseUnixCommand(cmd string) ([]string, error) {
|
||||||
|
return shlex.Split(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseWindowsCommand parses windows command lines and
|
||||||
|
// returns the command and the arguments as an array. It
|
||||||
|
// should be able to parse commonly used command lines.
|
||||||
|
// Only basic syntax is supported:
|
||||||
|
// - spaces in double quotes are not token delimiters
|
||||||
|
// - double quotes are escaped by either backspace or another double quote
|
||||||
|
// - except for the above case backspaces are path separators (not special)
|
||||||
|
//
|
||||||
|
// Many sources point out that escaping quotes using backslash can be unsafe.
|
||||||
|
// Use two double quotes when possible. (Source: http://stackoverflow.com/a/31413730/2616179 )
|
||||||
|
//
|
||||||
|
// This function has to be used on Windows instead
|
||||||
|
// of the shlex package because this function treats backslash
|
||||||
|
// characters properly.
|
||||||
|
func parseWindowsCommand(cmd string) []string {
|
||||||
|
const backslash = '\\'
|
||||||
|
const quote = '"'
|
||||||
|
|
||||||
|
var parts []string
|
||||||
|
var part string
|
||||||
|
var inQuotes bool
|
||||||
|
var lastRune rune
|
||||||
|
|
||||||
|
for i, ch := range cmd {
|
||||||
|
|
||||||
|
if i != 0 {
|
||||||
|
lastRune = rune(cmd[i-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == backslash {
|
||||||
|
// put it in the part - for now we don't know if it's an
|
||||||
|
// escaping char or path separator
|
||||||
|
part += string(ch)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch == quote {
|
||||||
|
if lastRune == backslash {
|
||||||
|
// remove the backslash from the part and add the escaped quote instead
|
||||||
|
part = part[:len(part)-1]
|
||||||
|
part += string(ch)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if lastRune == quote {
|
||||||
|
// revert the last change of the inQuotes state
|
||||||
|
// it was an escaping quote
|
||||||
|
inQuotes = !inQuotes
|
||||||
|
part += string(ch)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal escaping quotes
|
||||||
|
inQuotes = !inQuotes
|
||||||
|
continue
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 {
|
||||||
|
parts = append(parts, part)
|
||||||
|
part = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
part += string(ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(part) > 0 {
|
||||||
|
parts = append(parts, part)
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts
|
||||||
|
}
|
145
vendor/github.com/caddyserver/caddy/controller.go
generated
vendored
Normal file
145
vendor/github.com/caddyserver/caddy/controller.go
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/caddyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Controller is given to the setup function of directives which
|
||||||
|
// gives them access to be able to read tokens with which to
|
||||||
|
// configure themselves. It also stores state for the setup
|
||||||
|
// functions, can get the current context, and can be used to
|
||||||
|
// identify a particular server block using the Key field.
|
||||||
|
type Controller struct {
|
||||||
|
caddyfile.Dispenser
|
||||||
|
|
||||||
|
// The instance in which the setup is occurring
|
||||||
|
instance *Instance
|
||||||
|
|
||||||
|
// Key is the key from the top of the server block, usually
|
||||||
|
// an address, hostname, or identifier of some sort.
|
||||||
|
Key string
|
||||||
|
|
||||||
|
// OncePerServerBlock is a function that executes f
|
||||||
|
// exactly once per server block, no matter how many
|
||||||
|
// hosts are associated with it. If it is the first
|
||||||
|
// time, the function f is executed immediately
|
||||||
|
// (not deferred) and may return an error which is
|
||||||
|
// returned by OncePerServerBlock.
|
||||||
|
OncePerServerBlock func(f func() error) error
|
||||||
|
|
||||||
|
// ServerBlockIndex is the 0-based index of the
|
||||||
|
// server block as it appeared in the input.
|
||||||
|
ServerBlockIndex int
|
||||||
|
|
||||||
|
// ServerBlockKeyIndex is the 0-based index of this
|
||||||
|
// key as it appeared in the input at the head of the
|
||||||
|
// server block.
|
||||||
|
ServerBlockKeyIndex int
|
||||||
|
|
||||||
|
// ServerBlockKeys is a list of keys that are
|
||||||
|
// associated with this server block. All these
|
||||||
|
// keys, consequently, share the same tokens.
|
||||||
|
ServerBlockKeys []string
|
||||||
|
|
||||||
|
// ServerBlockStorage is used by a directive's
|
||||||
|
// setup function to persist state between all
|
||||||
|
// the keys on a server block.
|
||||||
|
ServerBlockStorage interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerType gets the name of the server type that is being set up.
|
||||||
|
func (c *Controller) ServerType() string {
|
||||||
|
return c.instance.serverType
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnFirstStartup adds fn to the list of callback functions to execute
|
||||||
|
// when the server is about to be started NOT as part of a restart.
|
||||||
|
func (c *Controller) OnFirstStartup(fn func() error) {
|
||||||
|
c.instance.OnFirstStartup = append(c.instance.OnFirstStartup, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnStartup adds fn to the list of callback functions to execute
|
||||||
|
// when the server is about to be started (including restarts).
|
||||||
|
func (c *Controller) OnStartup(fn func() error) {
|
||||||
|
c.instance.OnStartup = append(c.instance.OnStartup, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnRestart adds fn to the list of callback functions to execute
|
||||||
|
// when the server is about to be restarted.
|
||||||
|
func (c *Controller) OnRestart(fn func() error) {
|
||||||
|
c.instance.OnRestart = append(c.instance.OnRestart, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnRestartFailed adds fn to the list of callback functions to execute
|
||||||
|
// if the server failed to restart.
|
||||||
|
func (c *Controller) OnRestartFailed(fn func() error) {
|
||||||
|
c.instance.OnRestartFailed = append(c.instance.OnRestartFailed, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnShutdown adds fn to the list of callback functions to execute
|
||||||
|
// when the server is about to be shut down (including restarts).
|
||||||
|
func (c *Controller) OnShutdown(fn func() error) {
|
||||||
|
c.instance.OnShutdown = append(c.instance.OnShutdown, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnFinalShutdown adds fn to the list of callback functions to execute
|
||||||
|
// when the server is about to be shut down NOT as part of a restart.
|
||||||
|
func (c *Controller) OnFinalShutdown(fn func() error) {
|
||||||
|
c.instance.OnFinalShutdown = append(c.instance.OnFinalShutdown, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context gets the context associated with the instance associated with c.
|
||||||
|
func (c *Controller) Context() Context {
|
||||||
|
return c.instance.context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get safely gets a value from the Instance's storage.
|
||||||
|
func (c *Controller) Get(key interface{}) interface{} {
|
||||||
|
c.instance.StorageMu.RLock()
|
||||||
|
defer c.instance.StorageMu.RUnlock()
|
||||||
|
return c.instance.Storage[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set safely sets a value on the Instance's storage.
|
||||||
|
func (c *Controller) Set(key, val interface{}) {
|
||||||
|
c.instance.StorageMu.Lock()
|
||||||
|
c.instance.Storage[key] = val
|
||||||
|
c.instance.StorageMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTestController creates a new Controller for
|
||||||
|
// the server type and input specified. The filename
|
||||||
|
// is "Testfile". If the server type is not empty and
|
||||||
|
// is plugged in, a context will be created so that
|
||||||
|
// the results of setup functions can be checked for
|
||||||
|
// correctness.
|
||||||
|
//
|
||||||
|
// Used only for testing, but exported so plugins can
|
||||||
|
// use this for convenience.
|
||||||
|
func NewTestController(serverType, input string) *Controller {
|
||||||
|
testInst := &Instance{serverType: serverType, Storage: make(map[interface{}]interface{})}
|
||||||
|
if stype, err := getServerType(serverType); err == nil {
|
||||||
|
testInst.context = stype.NewContext(testInst)
|
||||||
|
}
|
||||||
|
return &Controller{
|
||||||
|
instance: testInst,
|
||||||
|
Dispenser: caddyfile.NewDispenser("Testfile", strings.NewReader(input)),
|
||||||
|
OncePerServerBlock: func(f func() error) error { return f() },
|
||||||
|
}
|
||||||
|
}
|
25
vendor/github.com/caddyserver/caddy/go.mod
generated
vendored
Normal file
25
vendor/github.com/caddyserver/caddy/go.mod
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
module github.com/caddyserver/caddy
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/dustin/go-humanize v1.0.0
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||||
|
github.com/go-acme/lego/v3 v3.2.0
|
||||||
|
github.com/google/uuid v1.1.1
|
||||||
|
github.com/gorilla/websocket v1.4.0
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0
|
||||||
|
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a
|
||||||
|
github.com/klauspost/cpuid v1.2.0
|
||||||
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 // indirect
|
||||||
|
github.com/lucas-clemente/quic-go v0.13.1
|
||||||
|
github.com/mholt/certmagic v0.8.3
|
||||||
|
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||||
|
github.com/naoina/toml v0.1.1
|
||||||
|
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4
|
||||||
|
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
|
||||||
|
gopkg.in/mcuadros/go-syslog.v2 v2.2.1
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
|
gopkg.in/yaml.v2 v2.2.2
|
||||||
|
)
|
368
vendor/github.com/caddyserver/caddy/go.sum
generated
vendored
Normal file
368
vendor/github.com/caddyserver/caddy/go.sum
generated
vendored
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
|
||||||
|
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
|
||||||
|
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
|
||||||
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k=
|
||||||
|
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75 h1:3ILjVyslFbc4jl1w5TWuvvslFD/nDfR2H8tVaMVLrEY=
|
||||||
|
github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ=
|
||||||
|
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||||
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||||
|
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.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
|
||||||
|
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||||
|
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY=
|
||||||
|
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/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/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g=
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||||
|
github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
|
||||||
|
github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
|
||||||
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
|
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-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/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE=
|
||||||
|
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||||
|
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/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-acme/lego/v3 v3.1.0 h1:yanYFoYW8azFkCvJfIk7edWWfjkYkhDxe45ZsxoW4Xk=
|
||||||
|
github.com/go-acme/lego/v3 v3.1.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
|
||||||
|
github.com/go-acme/lego/v3 v3.2.0 h1:z0zvNlL1niv/1qA06V5X1BRC5PeLoGKAlVaWthXQz9c=
|
||||||
|
github.com/go-acme/lego/v3 v3.2.0/go.mod h1:074uqt+JS6plx+c9Xaiz6+L+GBb+7itGtzfcDM2AhEE=
|
||||||
|
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||||
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
|
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
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/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
|
||||||
|
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
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-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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||||
|
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/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
|
||||||
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
|
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.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4=
|
||||||
|
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a h1:BcF8coBl0QFVhe8vAMMlD+CV8EISiu9MGKLoj6ZEyJA=
|
||||||
|
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||||
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||||
|
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.2/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/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
|
||||||
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||||
|
github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA=
|
||||||
|
github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w=
|
||||||
|
github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA=
|
||||||
|
github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ=
|
||||||
|
github.com/lucas-clemente/quic-go v0.13.1 h1:CxtJTXQIh2aboCPk0M6vf530XOov6DZjVBiSE3nSj8s=
|
||||||
|
github.com/lucas-clemente/quic-go v0.13.1/go.mod h1:Vn3/Fb0/77b02SGhQk36KzOUmXgVpFfizUfW5WMaqyU=
|
||||||
|
github.com/marten-seemann/chacha20 v0.2.0 h1:f40vqzzx+3GdOmzQoItkLX5WLvHgPgyYqFFIO5Gh4hQ=
|
||||||
|
github.com/marten-seemann/chacha20 v0.2.0/go.mod h1:HSdjFau7GzYRj+ahFNwsO3ouVJr1HFkWoEwNDb4TMtE=
|
||||||
|
github.com/marten-seemann/qpack v0.1.0 h1:/0M7lkda/6mus9B8u34Asqm8ZhHAAt9Ho0vniNuVSVg=
|
||||||
|
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
|
||||||
|
github.com/marten-seemann/qtls v0.4.1 h1:YlT8QP3WCCvvok7MGEZkMldXbyqgr8oFg5/n8Gtbkks=
|
||||||
|
github.com/marten-seemann/qtls v0.4.1/go.mod h1:pxVXcHHw1pNIt8Qo0pwSYQEoZ8yYOOPXTCZLQQunvRc=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/mholt/certmagic v0.8.3 h1:JOUiX9IAZbbgyjNP2GY6v/6lorH+9GkZsc7ktMpGCSo=
|
||||||
|
github.com/mholt/certmagic v0.8.3/go.mod h1:91uJzK5K8IWtYQqTi5R2tsxV1pCde+wdGfaRaOZi6aQ=
|
||||||
|
github.com/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI=
|
||||||
|
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||||
|
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
|
||||||
|
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||||
|
github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8=
|
||||||
|
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||||
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
|
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
||||||
|
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
||||||
|
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||||
|
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
|
||||||
|
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||||
|
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
|
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4 h1:S9YlS71UNJIyS61OqGAmLXv3w5zclSidN+qwr80XxKs=
|
||||||
|
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
||||||
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
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/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
|
||||||
|
github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY=
|
||||||
|
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||||
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||||
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y=
|
||||||
|
golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
|
||||||
|
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
|
||||||
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
|
||||||
|
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a h1:Yu34BogBivvmu7SAzHHaB9nZWH5D1C+z3F1jyIaYZSQ=
|
||||||
|
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
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-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||||
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
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-20190921001708-c4c64cad1fd0/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
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.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/mcuadros/go-syslog.v2 v2.2.1 h1:60g8zx1BijSVSgLTzLCW9UC4/+i1Ih9jJ1DR5Tgp9vE=
|
||||||
|
gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
|
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
|
||||||
|
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
||||||
|
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
470
vendor/github.com/caddyserver/caddy/plugins.go
generated
vendored
Normal file
470
vendor/github.com/caddyserver/caddy/plugins.go
generated
vendored
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/caddyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are all the registered plugins.
|
||||||
|
var (
|
||||||
|
// serverTypes is a map of registered server types.
|
||||||
|
serverTypes = make(map[string]ServerType)
|
||||||
|
|
||||||
|
// plugins is a map of server type to map of plugin name to
|
||||||
|
// Plugin. These are the "general" plugins that may or may
|
||||||
|
// not be associated with a specific server type. If it's
|
||||||
|
// applicable to multiple server types or the server type is
|
||||||
|
// irrelevant, the key is empty string (""). But all plugins
|
||||||
|
// must have a name.
|
||||||
|
plugins = make(map[string]map[string]Plugin)
|
||||||
|
|
||||||
|
// eventHooks is a map of hook name to Hook. All hooks plugins
|
||||||
|
// must have a name.
|
||||||
|
eventHooks = &sync.Map{}
|
||||||
|
|
||||||
|
// parsingCallbacks maps server type to map of directive
|
||||||
|
// to list of callback functions. These aren't really
|
||||||
|
// plugins on their own, but are often registered from
|
||||||
|
// plugins.
|
||||||
|
parsingCallbacks = make(map[string]map[string][]ParsingCallback)
|
||||||
|
|
||||||
|
// caddyfileLoaders is the list of all Caddyfile loaders
|
||||||
|
// in registration order.
|
||||||
|
caddyfileLoaders []caddyfileLoader
|
||||||
|
)
|
||||||
|
|
||||||
|
// DescribePlugins returns a string describing the registered plugins.
|
||||||
|
func DescribePlugins() string {
|
||||||
|
pl := ListPlugins()
|
||||||
|
|
||||||
|
str := "Server types:\n"
|
||||||
|
for _, name := range pl["server_types"] {
|
||||||
|
str += " " + name + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
str += "\nCaddyfile loaders:\n"
|
||||||
|
for _, name := range pl["caddyfile_loaders"] {
|
||||||
|
str += " " + name + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pl["event_hooks"]) > 0 {
|
||||||
|
str += "\nEvent hook plugins:\n"
|
||||||
|
for _, name := range pl["event_hooks"] {
|
||||||
|
str += " hook." + name + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pl["clustering"]) > 0 {
|
||||||
|
str += "\nClustering plugins:\n"
|
||||||
|
for _, name := range pl["clustering"] {
|
||||||
|
str += " " + name + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str += "\nOther plugins:\n"
|
||||||
|
for _, name := range pl["others"] {
|
||||||
|
str += " " + name + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListPlugins makes a list of the registered plugins,
|
||||||
|
// keyed by plugin type.
|
||||||
|
func ListPlugins() map[string][]string {
|
||||||
|
p := make(map[string][]string)
|
||||||
|
|
||||||
|
// server type plugins
|
||||||
|
for name := range serverTypes {
|
||||||
|
p["server_types"] = append(p["server_types"], name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// caddyfile loaders in registration order
|
||||||
|
for _, loader := range caddyfileLoaders {
|
||||||
|
p["caddyfile_loaders"] = append(p["caddyfile_loaders"], loader.name)
|
||||||
|
}
|
||||||
|
if defaultCaddyfileLoader.name != "" {
|
||||||
|
p["caddyfile_loaders"] = append(p["caddyfile_loaders"], defaultCaddyfileLoader.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// List the event hook plugins
|
||||||
|
eventHooks.Range(func(k, _ interface{}) bool {
|
||||||
|
p["event_hooks"] = append(p["event_hooks"], k.(string))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
// alphabetize the rest of the plugins
|
||||||
|
var others []string
|
||||||
|
for stype, stypePlugins := range plugins {
|
||||||
|
for name := range stypePlugins {
|
||||||
|
var s string
|
||||||
|
if stype != "" {
|
||||||
|
s = stype + "."
|
||||||
|
}
|
||||||
|
s += name
|
||||||
|
others = append(others, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(others)
|
||||||
|
for _, name := range others {
|
||||||
|
p["others"] = append(p["others"], name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidDirectives returns the list of all directives that are
|
||||||
|
// recognized for the server type serverType. However, not all
|
||||||
|
// directives may be installed. This makes it possible to give
|
||||||
|
// more helpful error messages, like "did you mean ..." or
|
||||||
|
// "maybe you need to plug in ...".
|
||||||
|
func ValidDirectives(serverType string) []string {
|
||||||
|
stype, err := getServerType(serverType)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return stype.Directives()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerListener pairs a server to its listener and/or packetconn.
|
||||||
|
type ServerListener struct {
|
||||||
|
server Server
|
||||||
|
listener net.Listener
|
||||||
|
packet net.PacketConn
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalAddr returns the local network address of the packetconn. It returns
|
||||||
|
// nil when it is not set.
|
||||||
|
func (s ServerListener) LocalAddr() net.Addr {
|
||||||
|
if s.packet == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.packet.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr returns the listener's network address. It returns nil when it is
|
||||||
|
// not set.
|
||||||
|
func (s ServerListener) Addr() net.Addr {
|
||||||
|
if s.listener == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return s.listener.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context is a type which carries a server type through
|
||||||
|
// the load and setup phase; it maintains the state
|
||||||
|
// between loading the Caddyfile, then executing its
|
||||||
|
// directives, then making the servers for Caddy to
|
||||||
|
// manage. Typically, such state involves configuration
|
||||||
|
// structs, etc.
|
||||||
|
type Context interface {
|
||||||
|
// Called after the Caddyfile is parsed into server
|
||||||
|
// blocks but before the directives are executed,
|
||||||
|
// this method gives you an opportunity to inspect
|
||||||
|
// the server blocks and prepare for the execution
|
||||||
|
// of directives. Return the server blocks (which
|
||||||
|
// you may modify, if desired) and an error, if any.
|
||||||
|
// The first argument is the name or path to the
|
||||||
|
// configuration file (Caddyfile).
|
||||||
|
//
|
||||||
|
// This function can be a no-op and simply return its
|
||||||
|
// input if there is nothing to do here.
|
||||||
|
InspectServerBlocks(string, []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error)
|
||||||
|
|
||||||
|
// This is what Caddy calls to make server instances.
|
||||||
|
// By this time, all directives have been executed and,
|
||||||
|
// presumably, the context has enough state to produce
|
||||||
|
// server instances for Caddy to start.
|
||||||
|
MakeServers() ([]Server, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterServerType registers a server type srv by its
|
||||||
|
// name, typeName.
|
||||||
|
func RegisterServerType(typeName string, srv ServerType) {
|
||||||
|
if _, ok := serverTypes[typeName]; ok {
|
||||||
|
panic("server type already registered")
|
||||||
|
}
|
||||||
|
serverTypes[typeName] = srv
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerType contains information about a server type.
|
||||||
|
type ServerType struct {
|
||||||
|
// Function that returns the list of directives, in
|
||||||
|
// execution order, that are valid for this server
|
||||||
|
// type. Directives should be one word if possible
|
||||||
|
// and lower-cased.
|
||||||
|
Directives func() []string
|
||||||
|
|
||||||
|
// DefaultInput returns a default config input if none
|
||||||
|
// is otherwise loaded. This is optional, but highly
|
||||||
|
// recommended, otherwise a blank Caddyfile will be
|
||||||
|
// used.
|
||||||
|
DefaultInput func() Input
|
||||||
|
|
||||||
|
// The function that produces a new server type context.
|
||||||
|
// This will be called when a new Caddyfile is being
|
||||||
|
// loaded, parsed, and executed independently of any
|
||||||
|
// startup phases before this one. It's a way to keep
|
||||||
|
// each set of server instances separate and to reduce
|
||||||
|
// the amount of global state you need.
|
||||||
|
NewContext func(inst *Instance) Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin is a type which holds information about a plugin.
|
||||||
|
type Plugin struct {
|
||||||
|
// ServerType is the type of server this plugin is for.
|
||||||
|
// Can be empty if not applicable, or if the plugin
|
||||||
|
// can associate with any server type.
|
||||||
|
ServerType string
|
||||||
|
|
||||||
|
// Action is the plugin's setup function, if associated
|
||||||
|
// with a directive in the Caddyfile.
|
||||||
|
Action SetupFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterPlugin plugs in plugin. All plugins should register
|
||||||
|
// themselves, even if they do not perform an action associated
|
||||||
|
// with a directive. It is important for the process to know
|
||||||
|
// which plugins are available.
|
||||||
|
//
|
||||||
|
// The plugin MUST have a name: lower case and one word.
|
||||||
|
// If this plugin has an action, it must be the name of
|
||||||
|
// the directive that invokes it. A name is always required
|
||||||
|
// and must be unique for the server type.
|
||||||
|
func RegisterPlugin(name string, plugin Plugin) {
|
||||||
|
if name == "" {
|
||||||
|
panic("plugin must have a name")
|
||||||
|
}
|
||||||
|
if _, ok := plugins[plugin.ServerType]; !ok {
|
||||||
|
plugins[plugin.ServerType] = make(map[string]Plugin)
|
||||||
|
}
|
||||||
|
if _, dup := plugins[plugin.ServerType][name]; dup {
|
||||||
|
panic("plugin named " + name + " already registered for server type " + plugin.ServerType)
|
||||||
|
}
|
||||||
|
plugins[plugin.ServerType][name] = plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventName represents the name of an event used with event hooks.
|
||||||
|
type EventName string
|
||||||
|
|
||||||
|
// Define names for the various events
|
||||||
|
const (
|
||||||
|
StartupEvent EventName = "startup"
|
||||||
|
ShutdownEvent = "shutdown"
|
||||||
|
CertRenewEvent = "certrenew"
|
||||||
|
InstanceStartupEvent = "instancestartup"
|
||||||
|
InstanceRestartEvent = "instancerestart"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventHook is a type which holds information about a startup hook plugin.
|
||||||
|
type EventHook func(eventType EventName, eventInfo interface{}) error
|
||||||
|
|
||||||
|
// RegisterEventHook plugs in hook. All the hooks should register themselves
|
||||||
|
// and they must have a name.
|
||||||
|
func RegisterEventHook(name string, hook EventHook) {
|
||||||
|
if name == "" {
|
||||||
|
panic("event hook must have a name")
|
||||||
|
}
|
||||||
|
_, dup := eventHooks.LoadOrStore(name, hook)
|
||||||
|
if dup {
|
||||||
|
panic("hook named " + name + " already registered")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmitEvent executes the different hooks passing the EventType as an
|
||||||
|
// argument. This is a blocking function. Hook developers should
|
||||||
|
// use 'go' keyword if they don't want to block Caddy.
|
||||||
|
func EmitEvent(event EventName, info interface{}) {
|
||||||
|
eventHooks.Range(func(k, v interface{}) bool {
|
||||||
|
err := v.(EventHook)(event, info)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error on '%s' hook: %v", k.(string), err)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// cloneEventHooks return a clone of the event hooks *sync.Map
|
||||||
|
func cloneEventHooks() *sync.Map {
|
||||||
|
c := &sync.Map{}
|
||||||
|
eventHooks.Range(func(k, v interface{}) bool {
|
||||||
|
c.Store(k, v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// purgeEventHooks purges all event hooks from the map
|
||||||
|
func purgeEventHooks() {
|
||||||
|
eventHooks.Range(func(k, _ interface{}) bool {
|
||||||
|
eventHooks.Delete(k)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// restoreEventHooks restores eventHooks with a provided *sync.Map
|
||||||
|
func restoreEventHooks(m *sync.Map) {
|
||||||
|
// Purge old event hooks
|
||||||
|
purgeEventHooks()
|
||||||
|
|
||||||
|
// Restore event hooks
|
||||||
|
m.Range(func(k, v interface{}) bool {
|
||||||
|
eventHooks.Store(k, v)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsingCallback is a function that is called after
|
||||||
|
// a directive's setup functions have been executed
|
||||||
|
// for all the server blocks.
|
||||||
|
type ParsingCallback func(Context) error
|
||||||
|
|
||||||
|
// RegisterParsingCallback registers callback to be called after
|
||||||
|
// executing the directive afterDir for server type serverType.
|
||||||
|
func RegisterParsingCallback(serverType, afterDir string, callback ParsingCallback) {
|
||||||
|
if _, ok := parsingCallbacks[serverType]; !ok {
|
||||||
|
parsingCallbacks[serverType] = make(map[string][]ParsingCallback)
|
||||||
|
}
|
||||||
|
parsingCallbacks[serverType][afterDir] = append(parsingCallbacks[serverType][afterDir], callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupFunc is used to set up a plugin, or in other words,
|
||||||
|
// execute a directive. It will be called once per key for
|
||||||
|
// each server block it appears in.
|
||||||
|
type SetupFunc func(c *Controller) error
|
||||||
|
|
||||||
|
// DirectiveAction gets the action for directive dir of
|
||||||
|
// server type serverType.
|
||||||
|
func DirectiveAction(serverType, dir string) (SetupFunc, error) {
|
||||||
|
if stypePlugins, ok := plugins[serverType]; ok {
|
||||||
|
if plugin, ok := stypePlugins[dir]; ok {
|
||||||
|
return plugin.Action, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if genericPlugins, ok := plugins[""]; ok {
|
||||||
|
if plugin, ok := genericPlugins[dir]; ok {
|
||||||
|
return plugin.Action, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no action found for directive '%s' with server type '%s' (missing a plugin?)",
|
||||||
|
dir, serverType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loader is a type that can load a Caddyfile.
|
||||||
|
// It is passed the name of the server type.
|
||||||
|
// It returns an error only if something went
|
||||||
|
// wrong, not simply if there is no Caddyfile
|
||||||
|
// for this loader to load.
|
||||||
|
//
|
||||||
|
// A Loader should only load the Caddyfile if
|
||||||
|
// a certain condition or requirement is met,
|
||||||
|
// as returning a non-nil Input value along with
|
||||||
|
// another Loader will result in an error.
|
||||||
|
// In other words, loading the Caddyfile must
|
||||||
|
// be deliberate & deterministic, not haphazard.
|
||||||
|
//
|
||||||
|
// The exception is the default Caddyfile loader,
|
||||||
|
// which will be called only if no other Caddyfile
|
||||||
|
// loaders return a non-nil Input. The default
|
||||||
|
// loader may always return an Input value.
|
||||||
|
type Loader interface {
|
||||||
|
Load(serverType string) (Input, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoaderFunc is a convenience type similar to http.HandlerFunc
|
||||||
|
// that allows you to use a plain function as a Load() method.
|
||||||
|
type LoaderFunc func(serverType string) (Input, error)
|
||||||
|
|
||||||
|
// Load loads a Caddyfile.
|
||||||
|
func (lf LoaderFunc) Load(serverType string) (Input, error) {
|
||||||
|
return lf(serverType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterCaddyfileLoader registers loader named name.
|
||||||
|
func RegisterCaddyfileLoader(name string, loader Loader) {
|
||||||
|
caddyfileLoaders = append(caddyfileLoaders, caddyfileLoader{name: name, loader: loader})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaultCaddyfileLoader registers loader by name
|
||||||
|
// as the default Caddyfile loader if no others produce
|
||||||
|
// a Caddyfile. If another Caddyfile loader has already
|
||||||
|
// been set as the default, this replaces it.
|
||||||
|
//
|
||||||
|
// Do not call RegisterCaddyfileLoader on the same
|
||||||
|
// loader; that would be redundant.
|
||||||
|
func SetDefaultCaddyfileLoader(name string, loader Loader) {
|
||||||
|
defaultCaddyfileLoader = caddyfileLoader{name: name, loader: loader}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadCaddyfileInput iterates the registered Caddyfile loaders
|
||||||
|
// and, if needed, calls the default loader, to load a Caddyfile.
|
||||||
|
// It is an error if any of the loaders return an error or if
|
||||||
|
// more than one loader returns a Caddyfile.
|
||||||
|
func loadCaddyfileInput(serverType string) (Input, error) {
|
||||||
|
var loadedBy string
|
||||||
|
var caddyfileToUse Input
|
||||||
|
for _, l := range caddyfileLoaders {
|
||||||
|
cdyfile, err := l.loader.Load(serverType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("loading Caddyfile via %s: %v", l.name, err)
|
||||||
|
}
|
||||||
|
if cdyfile != nil {
|
||||||
|
if caddyfileToUse != nil {
|
||||||
|
return nil, fmt.Errorf("Caddyfile loaded multiple times; first by %s, then by %s", loadedBy, l.name)
|
||||||
|
}
|
||||||
|
loaderUsed = l
|
||||||
|
caddyfileToUse = cdyfile
|
||||||
|
loadedBy = l.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if caddyfileToUse == nil && defaultCaddyfileLoader.loader != nil {
|
||||||
|
cdyfile, err := defaultCaddyfileLoader.loader.Load(serverType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if cdyfile != nil {
|
||||||
|
loaderUsed = defaultCaddyfileLoader
|
||||||
|
caddyfileToUse = cdyfile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return caddyfileToUse, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnProcessExit is a list of functions to run when the process
|
||||||
|
// exits -- they are ONLY for cleanup and should not block,
|
||||||
|
// return errors, or do anything fancy. They will be run with
|
||||||
|
// every signal, even if "shutdown callbacks" are not executed.
|
||||||
|
// This variable must only be modified in the main goroutine
|
||||||
|
// from init() functions.
|
||||||
|
var OnProcessExit []func()
|
||||||
|
|
||||||
|
// caddyfileLoader pairs the name of a loader to the loader.
|
||||||
|
type caddyfileLoader struct {
|
||||||
|
name string
|
||||||
|
loader Loader
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultCaddyfileLoader caddyfileLoader // the default loader if all else fail
|
||||||
|
loaderUsed caddyfileLoader // the loader that was used (relevant for reloads)
|
||||||
|
)
|
22
vendor/github.com/caddyserver/caddy/rlimit_nonposix.go
generated
vendored
Normal file
22
vendor/github.com/caddyserver/caddy/rlimit_nonposix.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build windows plan9 nacl js
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
// checkFdlimit issues a warning if the OS limit for
|
||||||
|
// max file descriptors is below a recommended minimum.
|
||||||
|
func checkFdlimit() {
|
||||||
|
}
|
37
vendor/github.com/caddyserver/caddy/rlimit_posix.go
generated
vendored
Normal file
37
vendor/github.com/caddyserver/caddy/rlimit_posix.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build !windows,!plan9,!nacl,!js
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// checkFdlimit issues a warning if the OS limit for
|
||||||
|
// max file descriptors is below a recommended minimum.
|
||||||
|
func checkFdlimit() {
|
||||||
|
const min = 8192
|
||||||
|
|
||||||
|
// Warn if ulimit is too low for production sites
|
||||||
|
rlimit := &syscall.Rlimit{}
|
||||||
|
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimit)
|
||||||
|
if err == nil && rlimit.Cur < min {
|
||||||
|
fmt.Printf("WARNING: File descriptor limit %d is too low for production servers. "+
|
||||||
|
"At least %d is recommended. Fix with `ulimit -n %d`.\n", rlimit.Cur, min, min)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
108
vendor/github.com/caddyserver/caddy/sigtrap.go
generated
vendored
Normal file
108
vendor/github.com/caddyserver/caddy/sigtrap.go
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/telemetry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TrapSignals create signal handlers for all applicable signals for this
|
||||||
|
// system. If your Go program uses signals, this is a rather invasive
|
||||||
|
// function; best to implement them yourself in that case. Signals are not
|
||||||
|
// required for the caddy package to function properly, but this is a
|
||||||
|
// convenient way to allow the user to control this part of your program.
|
||||||
|
func TrapSignals() {
|
||||||
|
trapSignalsCrossPlatform()
|
||||||
|
trapSignalsPosix()
|
||||||
|
}
|
||||||
|
|
||||||
|
// trapSignalsCrossPlatform captures SIGINT, which triggers forceful
|
||||||
|
// shutdown that executes shutdown callbacks first. A second interrupt
|
||||||
|
// signal will exit the process immediately.
|
||||||
|
func trapSignalsCrossPlatform() {
|
||||||
|
go func() {
|
||||||
|
shutdown := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(shutdown, os.Interrupt)
|
||||||
|
|
||||||
|
for i := 0; true; i++ {
|
||||||
|
<-shutdown
|
||||||
|
|
||||||
|
if i > 0 {
|
||||||
|
log.Println("[INFO] SIGINT: Force quit")
|
||||||
|
for _, f := range OnProcessExit {
|
||||||
|
f() // important cleanup actions only
|
||||||
|
}
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("[INFO] SIGINT: Shutting down")
|
||||||
|
|
||||||
|
telemetry.AppendUnique("sigtrap", "SIGINT")
|
||||||
|
go telemetry.StopEmitting() // not guaranteed to finish in time; that's OK (just don't block!)
|
||||||
|
|
||||||
|
// important cleanup actions before shutdown callbacks
|
||||||
|
for _, f := range OnProcessExit {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
os.Exit(executeShutdownCallbacks("SIGINT"))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeShutdownCallbacks executes the shutdown callbacks as initiated
|
||||||
|
// by signame. It logs any errors and returns the recommended exit status.
|
||||||
|
// This function is idempotent; subsequent invocations always return 0.
|
||||||
|
func executeShutdownCallbacks(signame string) (exitCode int) {
|
||||||
|
shutdownCallbacksOnce.Do(func() {
|
||||||
|
// execute third-party shutdown hooks
|
||||||
|
EmitEvent(ShutdownEvent, signame)
|
||||||
|
|
||||||
|
errs := allShutdownCallbacks()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
for _, err := range errs {
|
||||||
|
log.Printf("[ERROR] %s shutdown: %v", signame, err)
|
||||||
|
}
|
||||||
|
exitCode = 4
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// allShutdownCallbacks executes all the shutdown callbacks
|
||||||
|
// for all the instances, and returns all the errors generated
|
||||||
|
// during their execution. An error executing one shutdown
|
||||||
|
// callback does not stop execution of others. Only one shutdown
|
||||||
|
// callback is executed at a time.
|
||||||
|
func allShutdownCallbacks() []error {
|
||||||
|
var errs []error
|
||||||
|
instancesMu.Lock()
|
||||||
|
for _, inst := range instances {
|
||||||
|
errs = append(errs, inst.ShutdownCallbacks()...)
|
||||||
|
}
|
||||||
|
instancesMu.Unlock()
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
// shutdownCallbacksOnce ensures that shutdown callbacks
|
||||||
|
// for all instances are only executed once.
|
||||||
|
var shutdownCallbacksOnce sync.Once
|
19
vendor/github.com/caddyserver/caddy/sigtrap_nonposix.go
generated
vendored
Normal file
19
vendor/github.com/caddyserver/caddy/sigtrap_nonposix.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build windows plan9 nacl js
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
func trapSignalsPosix() {}
|
114
vendor/github.com/caddyserver/caddy/sigtrap_posix.go
generated
vendored
Normal file
114
vendor/github.com/caddyserver/caddy/sigtrap_posix.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build !windows,!plan9,!nacl,!js
|
||||||
|
|
||||||
|
package caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/telemetry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// trapSignalsPosix captures POSIX-only signals.
|
||||||
|
func trapSignalsPosix() {
|
||||||
|
go func() {
|
||||||
|
sigchan := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
|
||||||
|
|
||||||
|
for sig := range sigchan {
|
||||||
|
switch sig {
|
||||||
|
case syscall.SIGQUIT:
|
||||||
|
log.Println("[INFO] SIGQUIT: Quitting process immediately")
|
||||||
|
for _, f := range OnProcessExit {
|
||||||
|
f() // only perform important cleanup actions
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
|
||||||
|
case syscall.SIGTERM:
|
||||||
|
log.Println("[INFO] SIGTERM: Shutting down servers then terminating")
|
||||||
|
exitCode := executeShutdownCallbacks("SIGTERM")
|
||||||
|
for _, f := range OnProcessExit {
|
||||||
|
f() // only perform important cleanup actions
|
||||||
|
}
|
||||||
|
err := Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] SIGTERM stop: %v", err)
|
||||||
|
exitCode = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
telemetry.AppendUnique("sigtrap", "SIGTERM")
|
||||||
|
go telemetry.StopEmitting() // won't finish in time, but that's OK - just don't block
|
||||||
|
|
||||||
|
os.Exit(exitCode)
|
||||||
|
|
||||||
|
case syscall.SIGUSR1:
|
||||||
|
log.Println("[INFO] SIGUSR1: Reloading")
|
||||||
|
go telemetry.AppendUnique("sigtrap", "SIGUSR1")
|
||||||
|
|
||||||
|
// Start with the existing Caddyfile
|
||||||
|
caddyfileToUse, inst, err := getCurrentCaddyfile()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] SIGUSR1: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if loaderUsed.loader == nil {
|
||||||
|
// This also should never happen
|
||||||
|
log.Println("[ERROR] SIGUSR1: no Caddyfile loader with which to reload Caddyfile")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the updated Caddyfile
|
||||||
|
newCaddyfile, err := loaderUsed.loader.Load(inst.serverType)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] SIGUSR1: loading updated Caddyfile: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if newCaddyfile != nil {
|
||||||
|
caddyfileToUse = newCaddyfile
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backup old event hooks
|
||||||
|
oldEventHooks := cloneEventHooks()
|
||||||
|
|
||||||
|
// Purge the old event hooks
|
||||||
|
purgeEventHooks()
|
||||||
|
|
||||||
|
// Kick off the restart; our work is done
|
||||||
|
EmitEvent(InstanceRestartEvent, nil)
|
||||||
|
_, err = inst.Restart(caddyfileToUse)
|
||||||
|
if err != nil {
|
||||||
|
restoreEventHooks(oldEventHooks)
|
||||||
|
|
||||||
|
log.Printf("[ERROR] SIGUSR1: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case syscall.SIGUSR2:
|
||||||
|
log.Println("[INFO] SIGUSR2: Upgrading")
|
||||||
|
go telemetry.AppendUnique("sigtrap", "SIGUSR2")
|
||||||
|
if err := Upgrade(); err != nil {
|
||||||
|
log.Printf("[ERROR] SIGUSR2: upgrading: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case syscall.SIGHUP:
|
||||||
|
// ignore; this signal is sometimes sent outside of the user's control
|
||||||
|
go telemetry.AppendUnique("sigtrap", "SIGHUP")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
310
vendor/github.com/caddyserver/caddy/telemetry/collection.go
generated
vendored
Normal file
310
vendor/github.com/caddyserver/caddy/telemetry/collection.go
generated
vendored
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 telemetry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hash/fnv"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init initializes this package so that it may
|
||||||
|
// be used. Do not call this function more than
|
||||||
|
// once. Init panics if it is called more than
|
||||||
|
// once or if the UUID value is empty. Once this
|
||||||
|
// function is called, the rest of the package
|
||||||
|
// may safely be used. If this function is not
|
||||||
|
// called, the collector functions may still be
|
||||||
|
// invoked, but they will be no-ops.
|
||||||
|
//
|
||||||
|
// Any metrics keys that are passed in the second
|
||||||
|
// argument will be permanently disabled for the
|
||||||
|
// lifetime of the process.
|
||||||
|
func Init(instanceID uuid.UUID, disabledMetricsKeys []string) {
|
||||||
|
if enabled {
|
||||||
|
panic("already initialized")
|
||||||
|
}
|
||||||
|
if str := instanceID.String(); str == "" ||
|
||||||
|
str == "00000000-0000-0000-0000-000000000000" {
|
||||||
|
panic("empty UUID")
|
||||||
|
}
|
||||||
|
instanceUUID = instanceID
|
||||||
|
disabledMetricsMu.Lock()
|
||||||
|
for _, key := range disabledMetricsKeys {
|
||||||
|
disabledMetrics[strings.TrimSpace(key)] = false
|
||||||
|
}
|
||||||
|
disabledMetricsMu.Unlock()
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartEmitting sends the current payload and begins the
|
||||||
|
// transmission cycle for updates. This is the first
|
||||||
|
// update sent, and future ones will be sent until
|
||||||
|
// StopEmitting is called.
|
||||||
|
//
|
||||||
|
// This function is non-blocking (it spawns a new goroutine).
|
||||||
|
//
|
||||||
|
// This function panics if it was called more than once.
|
||||||
|
// It is a no-op if this package was not initialized.
|
||||||
|
func StartEmitting() {
|
||||||
|
if !enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateTimerMu.Lock()
|
||||||
|
if updateTimer != nil {
|
||||||
|
updateTimerMu.Unlock()
|
||||||
|
panic("updates already started")
|
||||||
|
}
|
||||||
|
updateTimerMu.Unlock()
|
||||||
|
updateMu.Lock()
|
||||||
|
if updating {
|
||||||
|
updateMu.Unlock()
|
||||||
|
panic("update already in progress")
|
||||||
|
}
|
||||||
|
updateMu.Unlock()
|
||||||
|
go logEmit(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopEmitting sends the current payload and terminates
|
||||||
|
// the update cycle. No more updates will be sent.
|
||||||
|
//
|
||||||
|
// It is a no-op if the package was never initialized
|
||||||
|
// or if emitting was never started.
|
||||||
|
//
|
||||||
|
// NOTE: This function is blocking. Run in a goroutine if
|
||||||
|
// you want to guarantee no blocking at critical times
|
||||||
|
// like exiting the program.
|
||||||
|
func StopEmitting() {
|
||||||
|
if !enabled {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateTimerMu.Lock()
|
||||||
|
if updateTimer == nil {
|
||||||
|
updateTimerMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateTimerMu.Unlock()
|
||||||
|
logEmit(true) // likely too early; may take minutes to return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset empties the current payload buffer.
|
||||||
|
func Reset() {
|
||||||
|
resetBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set puts a value in the buffer to be included
|
||||||
|
// in the next emission. It overwrites any
|
||||||
|
// previous value.
|
||||||
|
//
|
||||||
|
// This function is safe for multiple goroutines,
|
||||||
|
// and it is recommended to call this using the
|
||||||
|
// go keyword after the call to SendHello so it
|
||||||
|
// doesn't block crucial code.
|
||||||
|
func Set(key string, val interface{}) {
|
||||||
|
if !enabled || isDisabled(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferMu.Lock()
|
||||||
|
if _, ok := buffer[key]; !ok {
|
||||||
|
if bufferItemCount >= maxBufferItems {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferItemCount++
|
||||||
|
}
|
||||||
|
buffer[key] = val
|
||||||
|
bufferMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNested puts a value in the buffer to be included
|
||||||
|
// in the next emission, nested under the top-level key
|
||||||
|
// as subkey. It overwrites any previous value.
|
||||||
|
//
|
||||||
|
// This function is safe for multiple goroutines,
|
||||||
|
// and it is recommended to call this using the
|
||||||
|
// go keyword after the call to SendHello so it
|
||||||
|
// doesn't block crucial code.
|
||||||
|
func SetNested(key, subkey string, val interface{}) {
|
||||||
|
if !enabled || isDisabled(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferMu.Lock()
|
||||||
|
if topLevel, ok1 := buffer[key]; ok1 {
|
||||||
|
topLevelMap, ok2 := topLevel.(map[string]interface{})
|
||||||
|
if !ok2 {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
log.Printf("[PANIC] Telemetry: key %s is already used for non-nested-map value", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, ok3 := topLevelMap[subkey]; !ok3 {
|
||||||
|
// don't exceed max buffer size
|
||||||
|
if bufferItemCount >= maxBufferItems {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferItemCount++
|
||||||
|
}
|
||||||
|
topLevelMap[subkey] = val
|
||||||
|
} else {
|
||||||
|
// don't exceed max buffer size
|
||||||
|
if bufferItemCount >= maxBufferItems {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferItemCount++
|
||||||
|
buffer[key] = map[string]interface{}{subkey: val}
|
||||||
|
}
|
||||||
|
bufferMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends value to a list named key.
|
||||||
|
// If key is new, a new list will be created.
|
||||||
|
// If key maps to a type that is not a list,
|
||||||
|
// a panic is logged, and this is a no-op.
|
||||||
|
func Append(key string, value interface{}) {
|
||||||
|
if !enabled || isDisabled(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferMu.Lock()
|
||||||
|
if bufferItemCount >= maxBufferItems {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: Test this...
|
||||||
|
bufVal, inBuffer := buffer[key]
|
||||||
|
sliceVal, sliceOk := bufVal.([]interface{})
|
||||||
|
if inBuffer && !sliceOk {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
log.Printf("[PANIC] Telemetry: key %s already used for non-slice value", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if sliceVal == nil {
|
||||||
|
buffer[key] = []interface{}{value}
|
||||||
|
} else if sliceOk {
|
||||||
|
buffer[key] = append(sliceVal, value)
|
||||||
|
}
|
||||||
|
bufferItemCount++
|
||||||
|
bufferMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendUnique adds value to a set named key.
|
||||||
|
// Set items are unordered. Values in the set
|
||||||
|
// are unique, but how many times they are
|
||||||
|
// appended is counted. The value must be
|
||||||
|
// hashable.
|
||||||
|
//
|
||||||
|
// If key is new, a new set will be created for
|
||||||
|
// values with that key. If key maps to a type
|
||||||
|
// that is not a counting set, a panic is logged,
|
||||||
|
// and this is a no-op.
|
||||||
|
func AppendUnique(key string, value interface{}) {
|
||||||
|
if !enabled || isDisabled(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferMu.Lock()
|
||||||
|
bufVal, inBuffer := buffer[key]
|
||||||
|
setVal, setOk := bufVal.(countingSet)
|
||||||
|
if inBuffer && !setOk {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
log.Printf("[PANIC] Telemetry: key %s already used for non-counting-set value", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if setVal == nil {
|
||||||
|
// ensure the buffer is not too full, then add new unique value
|
||||||
|
if bufferItemCount >= maxBufferItems {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buffer[key] = countingSet{value: 1}
|
||||||
|
bufferItemCount++
|
||||||
|
} else if setOk {
|
||||||
|
// unique value already exists, so just increment counter
|
||||||
|
setVal[value]++
|
||||||
|
}
|
||||||
|
bufferMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds amount to a value named key.
|
||||||
|
// If it does not exist, it is created with
|
||||||
|
// a value of 1. If key maps to a type that
|
||||||
|
// is not an integer, a panic is logged,
|
||||||
|
// and this is a no-op.
|
||||||
|
func Add(key string, amount int) {
|
||||||
|
atomicAdd(key, amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment is a shortcut for Add(key, 1)
|
||||||
|
func Increment(key string) {
|
||||||
|
atomicAdd(key, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// atomicAdd adds amount (negative to subtract)
|
||||||
|
// to key.
|
||||||
|
func atomicAdd(key string, amount int) {
|
||||||
|
if !enabled || isDisabled(key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferMu.Lock()
|
||||||
|
bufVal, inBuffer := buffer[key]
|
||||||
|
intVal, intOk := bufVal.(int)
|
||||||
|
if inBuffer && !intOk {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
log.Printf("[PANIC] Telemetry: key %s already used for non-integer value", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !inBuffer {
|
||||||
|
if bufferItemCount >= maxBufferItems {
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bufferItemCount++
|
||||||
|
}
|
||||||
|
buffer[key] = intVal + amount
|
||||||
|
bufferMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastHash hashes input using a 32-bit hashing algorithm
|
||||||
|
// that is fast, and returns the hash as a hex-encoded string.
|
||||||
|
// Do not use this for cryptographic purposes.
|
||||||
|
func FastHash(input []byte) string {
|
||||||
|
h := fnv.New32a()
|
||||||
|
if _, err := h.Write(input); err != nil {
|
||||||
|
log.Println("[ERROR] failed to write bytes: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%x", h.Sum32())
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDisabled returns whether key is
|
||||||
|
// a disabled metric key. ALL collection
|
||||||
|
// functions should call this and not
|
||||||
|
// save the value if this returns true.
|
||||||
|
func isDisabled(key string) bool {
|
||||||
|
// for keys that are augmented with data, such as
|
||||||
|
// "tls_client_hello_ua:<hash>", just
|
||||||
|
// check the prefix "tls_client_hello_ua"
|
||||||
|
checkKey := key
|
||||||
|
if idx := strings.Index(key, ":"); idx > -1 {
|
||||||
|
checkKey = key[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
disabledMetricsMu.RLock()
|
||||||
|
_, ok := disabledMetrics[checkKey]
|
||||||
|
disabledMetricsMu.RUnlock()
|
||||||
|
return ok
|
||||||
|
}
|
428
vendor/github.com/caddyserver/caddy/telemetry/telemetry.go
generated
vendored
Normal file
428
vendor/github.com/caddyserver/caddy/telemetry/telemetry.go
generated
vendored
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 telemetry implements the client for server-side telemetry
|
||||||
|
// of the network. Functions in this package are synchronous and blocking
|
||||||
|
// unless otherwise specified. For convenience, most functions here do
|
||||||
|
// not return errors, but errors are logged to the standard logger.
|
||||||
|
//
|
||||||
|
// To use this package, first call Init(). You can then call any of the
|
||||||
|
// collection/aggregation functions. Call StartEmitting() when you are
|
||||||
|
// ready to begin sending telemetry updates.
|
||||||
|
//
|
||||||
|
// When collecting metrics (functions like Set, AppendUnique, or Increment),
|
||||||
|
// it may be desirable and even recommended to invoke them in a new
|
||||||
|
// goroutine in case there is lock contention; they are thread-safe (unless
|
||||||
|
// noted), and you may not want them to block the main thread of execution.
|
||||||
|
// However, sometimes blocking may be necessary too; for example, adding
|
||||||
|
// startup metrics to the buffer before the call to StartEmitting().
|
||||||
|
//
|
||||||
|
// This package is designed to be as fast and space-efficient as reasonably
|
||||||
|
// possible, so that it does not disrupt the flow of execution.
|
||||||
|
package telemetry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// logEmit calls emit and then logs the error, if any.
|
||||||
|
// See docs for emit.
|
||||||
|
func logEmit(final bool) {
|
||||||
|
err := emit(final)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Sending telemetry: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// emit sends an update to the telemetry server.
|
||||||
|
// Set final to true if this is the last call to emit.
|
||||||
|
// If final is true, no future updates will be scheduled.
|
||||||
|
// Otherwise, the next update will be scheduled.
|
||||||
|
func emit(final bool) error {
|
||||||
|
if !enabled {
|
||||||
|
return fmt.Errorf("telemetry not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// some metrics are updated/set at time of emission
|
||||||
|
setEmitTimeMetrics()
|
||||||
|
|
||||||
|
// ensure only one update happens at a time;
|
||||||
|
// skip update if previous one still in progress
|
||||||
|
updateMu.Lock()
|
||||||
|
if updating {
|
||||||
|
updateMu.Unlock()
|
||||||
|
log.Println("[NOTICE] Skipping this telemetry update because previous one is still working")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
updating = true
|
||||||
|
updateMu.Unlock()
|
||||||
|
defer func() {
|
||||||
|
updateMu.Lock()
|
||||||
|
updating = false
|
||||||
|
updateMu.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// terminate any pending update if this is the last one
|
||||||
|
if final {
|
||||||
|
stopUpdateTimer()
|
||||||
|
}
|
||||||
|
|
||||||
|
payloadBytes, err := makePayloadAndResetBuffer()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// this will hold the server's reply
|
||||||
|
var reply Response
|
||||||
|
|
||||||
|
// transmit the payload - use a loop to retry in case of failure
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
if i > 0 && err != nil {
|
||||||
|
// don't hammer the server; first failure might have been
|
||||||
|
// a fluke, but back off more after that
|
||||||
|
log.Printf("[WARNING] Sending telemetry (attempt %d): %v - backing off and retrying", i, err)
|
||||||
|
time.Sleep(time.Duration((i+1)*(i+1)*(i+1)) * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send it
|
||||||
|
var resp *http.Response
|
||||||
|
resp, err = httpClient.Post(endpoint+instanceUUID.String(), "application/json", bytes.NewReader(payloadBytes))
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for any special-case response codes
|
||||||
|
if resp.StatusCode == http.StatusGone {
|
||||||
|
// the endpoint has been deprecated and is no longer servicing clients
|
||||||
|
err = fmt.Errorf("telemetry server replied with HTTP %d; upgrade required", resp.StatusCode)
|
||||||
|
if clen := resp.Header.Get("Content-Length"); clen != "0" && clen != "" {
|
||||||
|
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
log.Printf("[ERROR] Reading response body from server: %v", readErr)
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("%v - %s", err, bodyBytes)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
reply.Stop = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if resp.StatusCode == http.StatusUnavailableForLegalReasons {
|
||||||
|
// the endpoint is unavailable, at least to this client, for legal reasons (!)
|
||||||
|
err = fmt.Errorf("telemetry server replied with HTTP %d %s: please consult the project website and developers for guidance", resp.StatusCode, resp.Status)
|
||||||
|
if clen := resp.Header.Get("Content-Length"); clen != "0" && clen != "" {
|
||||||
|
bodyBytes, readErr := ioutil.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
log.Printf("[ERROR] Reading response body from server: %v", readErr)
|
||||||
|
}
|
||||||
|
err = fmt.Errorf("%v - %s", err, bodyBytes)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
reply.Stop = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// okay, ensure we can interpret the response
|
||||||
|
if ct := resp.Header.Get("Content-Type"); (resp.StatusCode < 300 || resp.StatusCode >= 400) &&
|
||||||
|
!strings.Contains(ct, "json") {
|
||||||
|
err = fmt.Errorf("telemetry server replied with unknown content-type: '%s' and HTTP %s", ct, resp.Status)
|
||||||
|
resp.Body.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the response body
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&reply)
|
||||||
|
resp.Body.Close() // close response body as soon as we're done with it
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the list of enabled/disabled keys, if any
|
||||||
|
for _, key := range reply.EnableKeys {
|
||||||
|
disabledMetricsMu.Lock()
|
||||||
|
// only re-enable this metric if it is temporarily disabled
|
||||||
|
if temp, ok := disabledMetrics[key]; ok && temp {
|
||||||
|
delete(disabledMetrics, key)
|
||||||
|
}
|
||||||
|
disabledMetricsMu.Unlock()
|
||||||
|
}
|
||||||
|
for _, key := range reply.DisableKeys {
|
||||||
|
disabledMetricsMu.Lock()
|
||||||
|
disabledMetrics[key] = true // all remotely-disabled keys are "temporarily" disabled
|
||||||
|
disabledMetricsMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure we didn't send the update too soon; if so,
|
||||||
|
// just wait and try again -- this is a special case of
|
||||||
|
// error that we handle differently, as you can see
|
||||||
|
if resp.StatusCode == http.StatusTooManyRequests {
|
||||||
|
if reply.NextUpdate <= 0 {
|
||||||
|
raStr := resp.Header.Get("Retry-After")
|
||||||
|
if ra, err := strconv.Atoi(raStr); err == nil {
|
||||||
|
reply.NextUpdate = time.Duration(ra) * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !final {
|
||||||
|
log.Printf("[NOTICE] Sending telemetry: we were too early; waiting %s before trying again", reply.NextUpdate)
|
||||||
|
time.Sleep(reply.NextUpdate)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else if resp.StatusCode >= 400 {
|
||||||
|
err = fmt.Errorf("telemetry server returned status code %d", resp.StatusCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err == nil && !final {
|
||||||
|
// (remember, if there was an error, we return it
|
||||||
|
// below, so it WILL get logged if it's supposed to)
|
||||||
|
log.Println("[INFO] Sending telemetry: success")
|
||||||
|
}
|
||||||
|
|
||||||
|
// even if there was an error after all retries, we should
|
||||||
|
// schedule the next update using our default update
|
||||||
|
// interval because the server might be healthy later
|
||||||
|
|
||||||
|
// ensure we won't slam the telemetry server; add a little variance
|
||||||
|
if reply.NextUpdate < 1*time.Second {
|
||||||
|
reply.NextUpdate = defaultUpdateInterval + time.Duration(rand.Int63n(int64(1*time.Minute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// schedule the next update (if this wasn't the last one and
|
||||||
|
// if the remote server didn't tell us to stop sending)
|
||||||
|
if !final && !reply.Stop {
|
||||||
|
updateTimerMu.Lock()
|
||||||
|
updateTimer = time.AfterFunc(reply.NextUpdate, func() {
|
||||||
|
logEmit(false)
|
||||||
|
})
|
||||||
|
updateTimerMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func stopUpdateTimer() {
|
||||||
|
updateTimerMu.Lock()
|
||||||
|
updateTimer.Stop()
|
||||||
|
updateTimer = nil
|
||||||
|
updateTimerMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setEmitTimeMetrics sets some metrics that should
|
||||||
|
// be recorded just before emitting.
|
||||||
|
func setEmitTimeMetrics() {
|
||||||
|
Set("goroutines", runtime.NumGoroutine())
|
||||||
|
|
||||||
|
var mem runtime.MemStats
|
||||||
|
runtime.ReadMemStats(&mem)
|
||||||
|
SetNested("memory", "heap_alloc", mem.HeapAlloc)
|
||||||
|
SetNested("memory", "sys", mem.Sys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// makePayloadAndResetBuffer prepares a payload
|
||||||
|
// by emptying the collection buffer. It returns
|
||||||
|
// the bytes of the payload to send to the server.
|
||||||
|
// Since the buffer is reset by this, if the
|
||||||
|
// resulting byte slice is lost, the payload is
|
||||||
|
// gone with it.
|
||||||
|
func makePayloadAndResetBuffer() ([]byte, error) {
|
||||||
|
bufCopy := resetBuffer()
|
||||||
|
|
||||||
|
// encode payload in preparation for transmission
|
||||||
|
payload := Payload{
|
||||||
|
InstanceID: instanceUUID.String(),
|
||||||
|
Timestamp: time.Now().UTC(),
|
||||||
|
Data: bufCopy,
|
||||||
|
}
|
||||||
|
return json.Marshal(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resetBuffer makes a local pointer to the buffer,
|
||||||
|
// then resets the buffer by assigning to be a newly-
|
||||||
|
// made value to clear it out, then sets the buffer
|
||||||
|
// item count to 0. It returns the copied pointer to
|
||||||
|
// the original map so the old buffer value can be
|
||||||
|
// used locally.
|
||||||
|
func resetBuffer() map[string]interface{} {
|
||||||
|
bufferMu.Lock()
|
||||||
|
bufCopy := buffer
|
||||||
|
buffer = make(map[string]interface{})
|
||||||
|
bufferItemCount = 0
|
||||||
|
bufferMu.Unlock()
|
||||||
|
return bufCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response contains the body of a response from the
|
||||||
|
// telemetry server.
|
||||||
|
type Response struct {
|
||||||
|
// NextUpdate is how long to wait before the next update.
|
||||||
|
NextUpdate time.Duration `json:"next_update"`
|
||||||
|
|
||||||
|
// Stop instructs the telemetry server to stop sending
|
||||||
|
// telemetry. This would only be done under extenuating
|
||||||
|
// circumstances, but we are prepared for it nonetheless.
|
||||||
|
Stop bool `json:"stop,omitempty"`
|
||||||
|
|
||||||
|
// Error will be populated with an error message, if any.
|
||||||
|
// This field should be empty if the status code is < 400.
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
|
||||||
|
// DisableKeys will contain a list of keys/metrics that
|
||||||
|
// should NOT be sent until further notice. The client
|
||||||
|
// must NOT store these items in its buffer or send them
|
||||||
|
// to the telemetry server while they are disabled. If
|
||||||
|
// this list and EnableKeys have the same value (which is
|
||||||
|
// not supposed to happen), this field should dominate.
|
||||||
|
DisableKeys []string `json:"disable_keys,omitempty"`
|
||||||
|
|
||||||
|
// EnableKeys will contain a list of keys/metrics that
|
||||||
|
// MAY be sent until further notice.
|
||||||
|
EnableKeys []string `json:"enable_keys,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payload is the data that gets sent to the telemetry server.
|
||||||
|
type Payload struct {
|
||||||
|
// The universally unique ID of the instance
|
||||||
|
InstanceID string `json:"instance_id"`
|
||||||
|
|
||||||
|
// The UTC timestamp of the transmission
|
||||||
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
|
||||||
|
// The timestamp before which the next update is expected
|
||||||
|
// (NOT populated by client - the server fills this in
|
||||||
|
// before it stores the data)
|
||||||
|
ExpectNext time.Time `json:"expect_next,omitempty"`
|
||||||
|
|
||||||
|
// The metrics
|
||||||
|
Data map[string]interface{} `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int returns the value of the data keyed by key
|
||||||
|
// if it is an integer; otherwise it returns 0.
|
||||||
|
func (p Payload) Int(key string) int {
|
||||||
|
val, _ := p.Data[key]
|
||||||
|
switch p.Data[key].(type) {
|
||||||
|
case int:
|
||||||
|
return val.(int)
|
||||||
|
case float64: // after JSON-decoding, int becomes float64...
|
||||||
|
return int(val.(float64))
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// countingSet implements a set that counts how many
|
||||||
|
// times a key is inserted. It marshals to JSON in a
|
||||||
|
// way such that keys are converted to values next
|
||||||
|
// to their associated counts.
|
||||||
|
type countingSet map[interface{}]int
|
||||||
|
|
||||||
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
|
// It converts the set to an array so that the values
|
||||||
|
// are JSON object values instead of keys, since keys
|
||||||
|
// are difficult to query in databases.
|
||||||
|
func (s countingSet) MarshalJSON() ([]byte, error) {
|
||||||
|
type Item struct {
|
||||||
|
Value interface{} `json:"value"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
var list []Item
|
||||||
|
|
||||||
|
for k, v := range s {
|
||||||
|
list = append(list, Item{Value: k, Count: v})
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// httpClient should be used for HTTP requests. It
|
||||||
|
// is configured with a timeout for reliability.
|
||||||
|
httpClient = http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSHandshakeTimeout: 30 * time.Second,
|
||||||
|
DisableKeepAlives: true,
|
||||||
|
},
|
||||||
|
Timeout: 1 * time.Minute,
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer holds the data that we are building up to send.
|
||||||
|
buffer = make(map[string]interface{})
|
||||||
|
bufferItemCount = 0
|
||||||
|
bufferMu sync.RWMutex // protects both the buffer and its count
|
||||||
|
|
||||||
|
// updating is used to ensure only one
|
||||||
|
// update happens at a time.
|
||||||
|
updating bool
|
||||||
|
updateMu sync.Mutex
|
||||||
|
|
||||||
|
// updateTimer fires off the next update.
|
||||||
|
// If no update is scheduled, this is nil.
|
||||||
|
updateTimer *time.Timer
|
||||||
|
updateTimerMu sync.Mutex
|
||||||
|
|
||||||
|
// disabledMetrics is a set of metric keys
|
||||||
|
// that should NOT be saved to the buffer
|
||||||
|
// or sent to the telemetry server. The value
|
||||||
|
// indicates whether the entry is temporary.
|
||||||
|
// If the value is true, it may be removed if
|
||||||
|
// the metric is re-enabled remotely later. If
|
||||||
|
// the value is false, it is permanent
|
||||||
|
// (presumably because the user explicitly
|
||||||
|
// disabled it) and can only be re-enabled
|
||||||
|
// with user consent.
|
||||||
|
disabledMetrics = make(map[string]bool)
|
||||||
|
disabledMetricsMu sync.RWMutex
|
||||||
|
|
||||||
|
// instanceUUID is the ID of the current instance.
|
||||||
|
// This MUST be set to emit telemetry.
|
||||||
|
// This MUST NOT be openly exposed to clients, for privacy.
|
||||||
|
instanceUUID uuid.UUID
|
||||||
|
|
||||||
|
// enabled indicates whether the package has
|
||||||
|
// been initialized and can be actively used.
|
||||||
|
enabled bool
|
||||||
|
|
||||||
|
// maxBufferItems is the maximum number of items we'll allow
|
||||||
|
// in the buffer before we start dropping new ones, in a
|
||||||
|
// rough (simple) attempt to keep memory use under control.
|
||||||
|
maxBufferItems = 100000
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// endpoint is the base URL to remote telemetry server;
|
||||||
|
// the instance ID will be appended to it.
|
||||||
|
endpoint = "https://telemetry.caddyserver.com/v1/update/"
|
||||||
|
|
||||||
|
// defaultUpdateInterval is how long to wait before emitting
|
||||||
|
// more telemetry data if all retires fail. This value is
|
||||||
|
// only used if the client receives a nonsensical value, or
|
||||||
|
// doesn't send one at all, or if a connection can't be made,
|
||||||
|
// likely indicating a problem with the server. Thus, this
|
||||||
|
// value should be a long duration to help alleviate extra
|
||||||
|
// load on the server.
|
||||||
|
defaultUpdateInterval = 1 * time.Hour
|
||||||
|
)
|
232
vendor/github.com/caddyserver/caddy/upgrade.go
generated
vendored
Normal file
232
vendor/github.com/caddyserver/caddy/upgrade.go
generated
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// Copyright 2015 Light Code Labs, LLC
|
||||||
|
//
|
||||||
|
// 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 caddy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// register CaddyfileInput with gob so it knows into
|
||||||
|
// which concrete type to decode an Input interface
|
||||||
|
gob.Register(CaddyfileInput{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUpgrade returns true if this process is part of an upgrade
|
||||||
|
// where a parent caddy process spawned this one to upgrade
|
||||||
|
// the binary.
|
||||||
|
func IsUpgrade() bool {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
return isUpgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade re-launches the process, preserving the listeners
|
||||||
|
// for a graceful upgrade. It does NOT load new configuration;
|
||||||
|
// it only starts the process anew with the current config.
|
||||||
|
// This makes it possible to perform zero-downtime binary upgrades.
|
||||||
|
//
|
||||||
|
// TODO: For more information when debugging, see:
|
||||||
|
// https://forum.golangbridge.org/t/bind-address-already-in-use-even-after-listener-closed/1510?u=matt
|
||||||
|
// https://github.com/mholt/shared-conn
|
||||||
|
func Upgrade() error {
|
||||||
|
log.Println("[INFO] Upgrading")
|
||||||
|
|
||||||
|
// use existing Caddyfile; do not change configuration during upgrade
|
||||||
|
currentCaddyfile, _, err := getCurrentCaddyfile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(os.Args) == 0 { // this should never happen, but...
|
||||||
|
os.Args = []string{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the child that it's a restart
|
||||||
|
env := os.Environ()
|
||||||
|
if !IsUpgrade() {
|
||||||
|
env = append(env, "CADDY__UPGRADE=1")
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare our payload to the child process
|
||||||
|
cdyfileGob := transferGob{
|
||||||
|
ListenerFds: make(map[string]uintptr),
|
||||||
|
Caddyfile: currentCaddyfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare a pipe to the fork's stdin so it can get the Caddyfile
|
||||||
|
rpipe, wpipe, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare a pipe that the child process will use to communicate
|
||||||
|
// its success with us by sending > 0 bytes
|
||||||
|
sigrpipe, sigwpipe, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// pass along relevant file descriptors to child process; ordering
|
||||||
|
// is very important since we rely on these being in certain positions.
|
||||||
|
extraFiles := []*os.File{sigwpipe} // fd 3
|
||||||
|
|
||||||
|
// add file descriptors of all the sockets
|
||||||
|
for i, j := 0, 0; ; i++ {
|
||||||
|
instancesMu.Lock()
|
||||||
|
if i >= len(instances) {
|
||||||
|
instancesMu.Unlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
inst := instances[i]
|
||||||
|
instancesMu.Unlock()
|
||||||
|
|
||||||
|
for _, s := range inst.servers {
|
||||||
|
gs, gracefulOk := s.server.(GracefulServer)
|
||||||
|
ln, lnOk := s.listener.(Listener)
|
||||||
|
pc, pcOk := s.packet.(PacketConn)
|
||||||
|
if gracefulOk {
|
||||||
|
if lnOk {
|
||||||
|
lnFile, _ := ln.File()
|
||||||
|
extraFiles = append(extraFiles, lnFile)
|
||||||
|
cdyfileGob.ListenerFds["tcp"+gs.Address()] = uintptr(4 + j) // 4 fds come before any of the listeners
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if pcOk {
|
||||||
|
pcFile, _ := pc.File()
|
||||||
|
extraFiles = append(extraFiles, pcFile)
|
||||||
|
cdyfileGob.ListenerFds["udp"+gs.Address()] = uintptr(4 + j) // 4 fds come before any of the listeners
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up the command
|
||||||
|
cmd := exec.Command(os.Args[0], os.Args[1:]...)
|
||||||
|
cmd.Stdin = rpipe // fd 0
|
||||||
|
cmd.Stdout = os.Stdout // fd 1
|
||||||
|
cmd.Stderr = os.Stderr // fd 2
|
||||||
|
cmd.ExtraFiles = extraFiles
|
||||||
|
cmd.Env = env
|
||||||
|
|
||||||
|
// spawn the child process
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// immediately close our dup'ed fds and the write end of our signal pipe
|
||||||
|
for _, f := range extraFiles {
|
||||||
|
err = f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// feed Caddyfile to the child
|
||||||
|
err = gob.NewEncoder(wpipe).Encode(cdyfileGob)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = wpipe.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine whether child startup succeeded
|
||||||
|
answer, readErr := ioutil.ReadAll(sigrpipe)
|
||||||
|
if len(answer) == 0 {
|
||||||
|
cmdErr := cmd.Wait() // get exit status
|
||||||
|
errStr := fmt.Sprintf("child failed to initialize: %v", cmdErr)
|
||||||
|
if readErr != nil {
|
||||||
|
errStr += fmt.Sprintf(" - additionally, error communicating with child process: %v", readErr)
|
||||||
|
}
|
||||||
|
return fmt.Errorf(errStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// looks like child is successful; we can exit gracefully.
|
||||||
|
log.Println("[INFO] Upgrade finished")
|
||||||
|
return Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// getCurrentCaddyfile gets the Caddyfile used by the
|
||||||
|
// current (first) Instance and returns both of them.
|
||||||
|
func getCurrentCaddyfile() (Input, *Instance, error) {
|
||||||
|
instancesMu.Lock()
|
||||||
|
if len(instances) == 0 {
|
||||||
|
instancesMu.Unlock()
|
||||||
|
return nil, nil, fmt.Errorf("no server instances are fully running")
|
||||||
|
}
|
||||||
|
inst := instances[0]
|
||||||
|
instancesMu.Unlock()
|
||||||
|
|
||||||
|
currentCaddyfile := inst.caddyfileInput
|
||||||
|
if currentCaddyfile == nil {
|
||||||
|
// hmm, did spawning process forget to close stdin? Anyhow, this is unusual.
|
||||||
|
return nil, inst, fmt.Errorf("no Caddyfile to reload (was stdin left open?)")
|
||||||
|
}
|
||||||
|
return currentCaddyfile, inst, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// signalSuccessToParent tells the parent our status using pipe at index 3.
|
||||||
|
// If this process is not a restart, this function does nothing.
|
||||||
|
// Calling this function once this process has successfully initialized
|
||||||
|
// is vital so that the parent process can unblock and kill itself.
|
||||||
|
// This function is idempotent; it executes at most once per process.
|
||||||
|
func signalSuccessToParent() {
|
||||||
|
signalParentOnce.Do(func() {
|
||||||
|
if IsUpgrade() {
|
||||||
|
ppipe := os.NewFile(3, "") // parent is reading from pipe at index 3
|
||||||
|
_, err := ppipe.Write([]byte("success")) // we must send some bytes to the parent
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] Communicating successful init to parent: %v", err)
|
||||||
|
}
|
||||||
|
ppipe.Close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// signalParentOnce is used to make sure that the parent is only
|
||||||
|
// signaled once; doing so more than once breaks whatever socket is
|
||||||
|
// at fd 4 (TODO: the reason for this is still unclear - to reproduce,
|
||||||
|
// call Stop() and Start() in succession at least once after a
|
||||||
|
// restart, then try loading first host of Caddyfile in the browser
|
||||||
|
// - this was pre-v0.9; this code and godoc is borrowed from the
|
||||||
|
// implementation then, but I'm not sure if it's been fixed yet, as
|
||||||
|
// of v0.10.7). Do not use this directly; call signalSuccessToParent
|
||||||
|
// instead.
|
||||||
|
var signalParentOnce sync.Once
|
||||||
|
|
||||||
|
// transferGob is used if this is a child process as part of
|
||||||
|
// a graceful upgrade; it is used to map listeners to their
|
||||||
|
// index in the list of inherited file descriptors. This
|
||||||
|
// variable is not safe for concurrent access.
|
||||||
|
var loadedGob transferGob
|
||||||
|
|
||||||
|
// transferGob maps bind address to index of the file descriptor
|
||||||
|
// in the Files array passed to the child process. It also contains
|
||||||
|
// the Caddyfile contents and any other state needed by the new process.
|
||||||
|
// Used only during graceful upgrades.
|
||||||
|
type transferGob struct {
|
||||||
|
ListenerFds map[string]uintptr
|
||||||
|
Caddyfile Input
|
||||||
|
}
|
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
Normal file
8
vendor/github.com/cespare/xxhash/v2/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- "1.x"
|
||||||
|
- master
|
||||||
|
env:
|
||||||
|
- TAGS=""
|
||||||
|
- TAGS="-tags purego"
|
||||||
|
script: go test $TAGS -v ./...
|
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
Normal file
22
vendor/github.com/cespare/xxhash/v2/LICENSE.txt
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
Copyright (c) 2016 Caleb Spare
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
67
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
Normal file
67
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# xxhash
|
||||||
|
|
||||||
|
[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash)
|
||||||
|
[![Build Status](https://travis-ci.org/cespare/xxhash.svg?branch=master)](https://travis-ci.org/cespare/xxhash)
|
||||||
|
|
||||||
|
xxhash is a Go implementation of the 64-bit
|
||||||
|
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
|
||||||
|
high-quality hashing algorithm that is much faster than anything in the Go
|
||||||
|
standard library.
|
||||||
|
|
||||||
|
This package provides a straightforward API:
|
||||||
|
|
||||||
|
```
|
||||||
|
func Sum64(b []byte) uint64
|
||||||
|
func Sum64String(s string) uint64
|
||||||
|
type Digest struct{ ... }
|
||||||
|
func New() *Digest
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Digest` type implements hash.Hash64. Its key methods are:
|
||||||
|
|
||||||
|
```
|
||||||
|
func (*Digest) Write([]byte) (int, error)
|
||||||
|
func (*Digest) WriteString(string) (int, error)
|
||||||
|
func (*Digest) Sum64() uint64
|
||||||
|
```
|
||||||
|
|
||||||
|
This implementation provides a fast pure-Go implementation and an even faster
|
||||||
|
assembly implementation for amd64.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
This package is in a module and the latest code is in version 2 of the module.
|
||||||
|
You need a version of Go with at least "minimal module compatibility" to use
|
||||||
|
github.com/cespare/xxhash/v2:
|
||||||
|
|
||||||
|
* 1.9.7+ for Go 1.9
|
||||||
|
* 1.10.3+ for Go 1.10
|
||||||
|
* Go 1.11 or later
|
||||||
|
|
||||||
|
I recommend using the latest release of Go.
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
Here are some quick benchmarks comparing the pure-Go and assembly
|
||||||
|
implementations of Sum64.
|
||||||
|
|
||||||
|
| input size | purego | asm |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 5 B | 979.66 MB/s | 1291.17 MB/s |
|
||||||
|
| 100 B | 7475.26 MB/s | 7973.40 MB/s |
|
||||||
|
| 4 KB | 17573.46 MB/s | 17602.65 MB/s |
|
||||||
|
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
|
||||||
|
|
||||||
|
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
|
||||||
|
the following commands under Go 1.11.2:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||||
|
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Projects using this package
|
||||||
|
|
||||||
|
- [InfluxDB](https://github.com/influxdata/influxdb)
|
||||||
|
- [Prometheus](https://github.com/prometheus/prometheus)
|
||||||
|
- [FreeCache](https://github.com/coocood/freecache)
|
3
vendor/github.com/cespare/xxhash/v2/go.mod
generated
vendored
Normal file
3
vendor/github.com/cespare/xxhash/v2/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module github.com/cespare/xxhash/v2
|
||||||
|
|
||||||
|
go 1.11
|
0
vendor/github.com/cespare/xxhash/v2/go.sum
generated
vendored
Normal file
0
vendor/github.com/cespare/xxhash/v2/go.sum
generated
vendored
Normal file
236
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
Normal file
236
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
|
||||||
|
// at http://cyan4973.github.io/xxHash/.
|
||||||
|
package xxhash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"math/bits"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
prime1 uint64 = 11400714785074694791
|
||||||
|
prime2 uint64 = 14029467366897019727
|
||||||
|
prime3 uint64 = 1609587929392839161
|
||||||
|
prime4 uint64 = 9650029242287828579
|
||||||
|
prime5 uint64 = 2870177450012600261
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
|
||||||
|
// possible in the Go code is worth a small (but measurable) performance boost
|
||||||
|
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
|
||||||
|
// convenience in the Go code in a few places where we need to intentionally
|
||||||
|
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
|
||||||
|
// result overflows a uint64).
|
||||||
|
var (
|
||||||
|
prime1v = prime1
|
||||||
|
prime2v = prime2
|
||||||
|
prime3v = prime3
|
||||||
|
prime4v = prime4
|
||||||
|
prime5v = prime5
|
||||||
|
)
|
||||||
|
|
||||||
|
// Digest implements hash.Hash64.
|
||||||
|
type Digest struct {
|
||||||
|
v1 uint64
|
||||||
|
v2 uint64
|
||||||
|
v3 uint64
|
||||||
|
v4 uint64
|
||||||
|
total uint64
|
||||||
|
mem [32]byte
|
||||||
|
n int // how much of mem is used
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new Digest that computes the 64-bit xxHash algorithm.
|
||||||
|
func New() *Digest {
|
||||||
|
var d Digest
|
||||||
|
d.Reset()
|
||||||
|
return &d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset clears the Digest's state so that it can be reused.
|
||||||
|
func (d *Digest) Reset() {
|
||||||
|
d.v1 = prime1v + prime2
|
||||||
|
d.v2 = prime2
|
||||||
|
d.v3 = 0
|
||||||
|
d.v4 = -prime1v
|
||||||
|
d.total = 0
|
||||||
|
d.n = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size always returns 8 bytes.
|
||||||
|
func (d *Digest) Size() int { return 8 }
|
||||||
|
|
||||||
|
// BlockSize always returns 32 bytes.
|
||||||
|
func (d *Digest) BlockSize() int { return 32 }
|
||||||
|
|
||||||
|
// Write adds more data to d. It always returns len(b), nil.
|
||||||
|
func (d *Digest) Write(b []byte) (n int, err error) {
|
||||||
|
n = len(b)
|
||||||
|
d.total += uint64(n)
|
||||||
|
|
||||||
|
if d.n+n < 32 {
|
||||||
|
// This new data doesn't even fill the current block.
|
||||||
|
copy(d.mem[d.n:], b)
|
||||||
|
d.n += n
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.n > 0 {
|
||||||
|
// Finish off the partial block.
|
||||||
|
copy(d.mem[d.n:], b)
|
||||||
|
d.v1 = round(d.v1, u64(d.mem[0:8]))
|
||||||
|
d.v2 = round(d.v2, u64(d.mem[8:16]))
|
||||||
|
d.v3 = round(d.v3, u64(d.mem[16:24]))
|
||||||
|
d.v4 = round(d.v4, u64(d.mem[24:32]))
|
||||||
|
b = b[32-d.n:]
|
||||||
|
d.n = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b) >= 32 {
|
||||||
|
// One or more full blocks left.
|
||||||
|
nw := writeBlocks(d, b)
|
||||||
|
b = b[nw:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store any remaining partial block.
|
||||||
|
copy(d.mem[:], b)
|
||||||
|
d.n = len(b)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum appends the current hash to b and returns the resulting slice.
|
||||||
|
func (d *Digest) Sum(b []byte) []byte {
|
||||||
|
s := d.Sum64()
|
||||||
|
return append(
|
||||||
|
b,
|
||||||
|
byte(s>>56),
|
||||||
|
byte(s>>48),
|
||||||
|
byte(s>>40),
|
||||||
|
byte(s>>32),
|
||||||
|
byte(s>>24),
|
||||||
|
byte(s>>16),
|
||||||
|
byte(s>>8),
|
||||||
|
byte(s),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum64 returns the current hash.
|
||||||
|
func (d *Digest) Sum64() uint64 {
|
||||||
|
var h uint64
|
||||||
|
|
||||||
|
if d.total >= 32 {
|
||||||
|
v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
|
||||||
|
h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
|
||||||
|
h = mergeRound(h, v1)
|
||||||
|
h = mergeRound(h, v2)
|
||||||
|
h = mergeRound(h, v3)
|
||||||
|
h = mergeRound(h, v4)
|
||||||
|
} else {
|
||||||
|
h = d.v3 + prime5
|
||||||
|
}
|
||||||
|
|
||||||
|
h += d.total
|
||||||
|
|
||||||
|
i, end := 0, d.n
|
||||||
|
for ; i+8 <= end; i += 8 {
|
||||||
|
k1 := round(0, u64(d.mem[i:i+8]))
|
||||||
|
h ^= k1
|
||||||
|
h = rol27(h)*prime1 + prime4
|
||||||
|
}
|
||||||
|
if i+4 <= end {
|
||||||
|
h ^= uint64(u32(d.mem[i:i+4])) * prime1
|
||||||
|
h = rol23(h)*prime2 + prime3
|
||||||
|
i += 4
|
||||||
|
}
|
||||||
|
for i < end {
|
||||||
|
h ^= uint64(d.mem[i]) * prime5
|
||||||
|
h = rol11(h) * prime1
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
h ^= h >> 33
|
||||||
|
h *= prime2
|
||||||
|
h ^= h >> 29
|
||||||
|
h *= prime3
|
||||||
|
h ^= h >> 32
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
magic = "xxh\x06"
|
||||||
|
marshaledSize = len(magic) + 8*5 + 32
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalBinary implements the encoding.BinaryMarshaler interface.
|
||||||
|
func (d *Digest) MarshalBinary() ([]byte, error) {
|
||||||
|
b := make([]byte, 0, marshaledSize)
|
||||||
|
b = append(b, magic...)
|
||||||
|
b = appendUint64(b, d.v1)
|
||||||
|
b = appendUint64(b, d.v2)
|
||||||
|
b = appendUint64(b, d.v3)
|
||||||
|
b = appendUint64(b, d.v4)
|
||||||
|
b = appendUint64(b, d.total)
|
||||||
|
b = append(b, d.mem[:d.n]...)
|
||||||
|
b = b[:len(b)+len(d.mem)-d.n]
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
|
||||||
|
func (d *Digest) UnmarshalBinary(b []byte) error {
|
||||||
|
if len(b) < len(magic) || string(b[:len(magic)]) != magic {
|
||||||
|
return errors.New("xxhash: invalid hash state identifier")
|
||||||
|
}
|
||||||
|
if len(b) != marshaledSize {
|
||||||
|
return errors.New("xxhash: invalid hash state size")
|
||||||
|
}
|
||||||
|
b = b[len(magic):]
|
||||||
|
b, d.v1 = consumeUint64(b)
|
||||||
|
b, d.v2 = consumeUint64(b)
|
||||||
|
b, d.v3 = consumeUint64(b)
|
||||||
|
b, d.v4 = consumeUint64(b)
|
||||||
|
b, d.total = consumeUint64(b)
|
||||||
|
copy(d.mem[:], b)
|
||||||
|
b = b[len(d.mem):]
|
||||||
|
d.n = int(d.total % uint64(len(d.mem)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUint64(b []byte, x uint64) []byte {
|
||||||
|
var a [8]byte
|
||||||
|
binary.LittleEndian.PutUint64(a[:], x)
|
||||||
|
return append(b, a[:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func consumeUint64(b []byte) ([]byte, uint64) {
|
||||||
|
x := u64(b)
|
||||||
|
return b[8:], x
|
||||||
|
}
|
||||||
|
|
||||||
|
func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
|
||||||
|
func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
|
||||||
|
|
||||||
|
func round(acc, input uint64) uint64 {
|
||||||
|
acc += input * prime2
|
||||||
|
acc = rol31(acc)
|
||||||
|
acc *= prime1
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeRound(acc, val uint64) uint64 {
|
||||||
|
val = round(0, val)
|
||||||
|
acc ^= val
|
||||||
|
acc = acc*prime1 + prime4
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) }
|
||||||
|
func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) }
|
||||||
|
func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
|
||||||
|
func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
|
||||||
|
func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
|
||||||
|
func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
|
||||||
|
func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
|
||||||
|
func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }
|
13
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
generated
vendored
Normal file
13
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !purego
|
||||||
|
|
||||||
|
package xxhash
|
||||||
|
|
||||||
|
// Sum64 computes the 64-bit xxHash digest of b.
|
||||||
|
//
|
||||||
|
//go:noescape
|
||||||
|
func Sum64(b []byte) uint64
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
func writeBlocks(d *Digest, b []byte) int
|
215
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
Normal file
215
vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
// +build !appengine
|
||||||
|
// +build gc
|
||||||
|
// +build !purego
|
||||||
|
|
||||||
|
#include "textflag.h"
|
||||||
|
|
||||||
|
// Register allocation:
|
||||||
|
// AX h
|
||||||
|
// CX pointer to advance through b
|
||||||
|
// DX n
|
||||||
|
// BX loop end
|
||||||
|
// R8 v1, k1
|
||||||
|
// R9 v2
|
||||||
|
// R10 v3
|
||||||
|
// R11 v4
|
||||||
|
// R12 tmp
|
||||||
|
// R13 prime1v
|
||||||
|
// R14 prime2v
|
||||||
|
// R15 prime4v
|
||||||
|
|
||||||
|
// round reads from and advances the buffer pointer in CX.
|
||||||
|
// It assumes that R13 has prime1v and R14 has prime2v.
|
||||||
|
#define round(r) \
|
||||||
|
MOVQ (CX), R12 \
|
||||||
|
ADDQ $8, CX \
|
||||||
|
IMULQ R14, R12 \
|
||||||
|
ADDQ R12, r \
|
||||||
|
ROLQ $31, r \
|
||||||
|
IMULQ R13, r
|
||||||
|
|
||||||
|
// mergeRound applies a merge round on the two registers acc and val.
|
||||||
|
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
|
||||||
|
#define mergeRound(acc, val) \
|
||||||
|
IMULQ R14, val \
|
||||||
|
ROLQ $31, val \
|
||||||
|
IMULQ R13, val \
|
||||||
|
XORQ val, acc \
|
||||||
|
IMULQ R13, acc \
|
||||||
|
ADDQ R15, acc
|
||||||
|
|
||||||
|
// func Sum64(b []byte) uint64
|
||||||
|
TEXT ·Sum64(SB), NOSPLIT, $0-32
|
||||||
|
// Load fixed primes.
|
||||||
|
MOVQ ·prime1v(SB), R13
|
||||||
|
MOVQ ·prime2v(SB), R14
|
||||||
|
MOVQ ·prime4v(SB), R15
|
||||||
|
|
||||||
|
// Load slice.
|
||||||
|
MOVQ b_base+0(FP), CX
|
||||||
|
MOVQ b_len+8(FP), DX
|
||||||
|
LEAQ (CX)(DX*1), BX
|
||||||
|
|
||||||
|
// The first loop limit will be len(b)-32.
|
||||||
|
SUBQ $32, BX
|
||||||
|
|
||||||
|
// Check whether we have at least one block.
|
||||||
|
CMPQ DX, $32
|
||||||
|
JLT noBlocks
|
||||||
|
|
||||||
|
// Set up initial state (v1, v2, v3, v4).
|
||||||
|
MOVQ R13, R8
|
||||||
|
ADDQ R14, R8
|
||||||
|
MOVQ R14, R9
|
||||||
|
XORQ R10, R10
|
||||||
|
XORQ R11, R11
|
||||||
|
SUBQ R13, R11
|
||||||
|
|
||||||
|
// Loop until CX > BX.
|
||||||
|
blockLoop:
|
||||||
|
round(R8)
|
||||||
|
round(R9)
|
||||||
|
round(R10)
|
||||||
|
round(R11)
|
||||||
|
|
||||||
|
CMPQ CX, BX
|
||||||
|
JLE blockLoop
|
||||||
|
|
||||||
|
MOVQ R8, AX
|
||||||
|
ROLQ $1, AX
|
||||||
|
MOVQ R9, R12
|
||||||
|
ROLQ $7, R12
|
||||||
|
ADDQ R12, AX
|
||||||
|
MOVQ R10, R12
|
||||||
|
ROLQ $12, R12
|
||||||
|
ADDQ R12, AX
|
||||||
|
MOVQ R11, R12
|
||||||
|
ROLQ $18, R12
|
||||||
|
ADDQ R12, AX
|
||||||
|
|
||||||
|
mergeRound(AX, R8)
|
||||||
|
mergeRound(AX, R9)
|
||||||
|
mergeRound(AX, R10)
|
||||||
|
mergeRound(AX, R11)
|
||||||
|
|
||||||
|
JMP afterBlocks
|
||||||
|
|
||||||
|
noBlocks:
|
||||||
|
MOVQ ·prime5v(SB), AX
|
||||||
|
|
||||||
|
afterBlocks:
|
||||||
|
ADDQ DX, AX
|
||||||
|
|
||||||
|
// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
|
||||||
|
ADDQ $24, BX
|
||||||
|
|
||||||
|
CMPQ CX, BX
|
||||||
|
JG fourByte
|
||||||
|
|
||||||
|
wordLoop:
|
||||||
|
// Calculate k1.
|
||||||
|
MOVQ (CX), R8
|
||||||
|
ADDQ $8, CX
|
||||||
|
IMULQ R14, R8
|
||||||
|
ROLQ $31, R8
|
||||||
|
IMULQ R13, R8
|
||||||
|
|
||||||
|
XORQ R8, AX
|
||||||
|
ROLQ $27, AX
|
||||||
|
IMULQ R13, AX
|
||||||
|
ADDQ R15, AX
|
||||||
|
|
||||||
|
CMPQ CX, BX
|
||||||
|
JLE wordLoop
|
||||||
|
|
||||||
|
fourByte:
|
||||||
|
ADDQ $4, BX
|
||||||
|
CMPQ CX, BX
|
||||||
|
JG singles
|
||||||
|
|
||||||
|
MOVL (CX), R8
|
||||||
|
ADDQ $4, CX
|
||||||
|
IMULQ R13, R8
|
||||||
|
XORQ R8, AX
|
||||||
|
|
||||||
|
ROLQ $23, AX
|
||||||
|
IMULQ R14, AX
|
||||||
|
ADDQ ·prime3v(SB), AX
|
||||||
|
|
||||||
|
singles:
|
||||||
|
ADDQ $4, BX
|
||||||
|
CMPQ CX, BX
|
||||||
|
JGE finalize
|
||||||
|
|
||||||
|
singlesLoop:
|
||||||
|
MOVBQZX (CX), R12
|
||||||
|
ADDQ $1, CX
|
||||||
|
IMULQ ·prime5v(SB), R12
|
||||||
|
XORQ R12, AX
|
||||||
|
|
||||||
|
ROLQ $11, AX
|
||||||
|
IMULQ R13, AX
|
||||||
|
|
||||||
|
CMPQ CX, BX
|
||||||
|
JL singlesLoop
|
||||||
|
|
||||||
|
finalize:
|
||||||
|
MOVQ AX, R12
|
||||||
|
SHRQ $33, R12
|
||||||
|
XORQ R12, AX
|
||||||
|
IMULQ R14, AX
|
||||||
|
MOVQ AX, R12
|
||||||
|
SHRQ $29, R12
|
||||||
|
XORQ R12, AX
|
||||||
|
IMULQ ·prime3v(SB), AX
|
||||||
|
MOVQ AX, R12
|
||||||
|
SHRQ $32, R12
|
||||||
|
XORQ R12, AX
|
||||||
|
|
||||||
|
MOVQ AX, ret+24(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// writeBlocks uses the same registers as above except that it uses AX to store
|
||||||
|
// the d pointer.
|
||||||
|
|
||||||
|
// func writeBlocks(d *Digest, b []byte) int
|
||||||
|
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
|
||||||
|
// Load fixed primes needed for round.
|
||||||
|
MOVQ ·prime1v(SB), R13
|
||||||
|
MOVQ ·prime2v(SB), R14
|
||||||
|
|
||||||
|
// Load slice.
|
||||||
|
MOVQ b_base+8(FP), CX
|
||||||
|
MOVQ b_len+16(FP), DX
|
||||||
|
LEAQ (CX)(DX*1), BX
|
||||||
|
SUBQ $32, BX
|
||||||
|
|
||||||
|
// Load vN from d.
|
||||||
|
MOVQ d+0(FP), AX
|
||||||
|
MOVQ 0(AX), R8 // v1
|
||||||
|
MOVQ 8(AX), R9 // v2
|
||||||
|
MOVQ 16(AX), R10 // v3
|
||||||
|
MOVQ 24(AX), R11 // v4
|
||||||
|
|
||||||
|
// We don't need to check the loop condition here; this function is
|
||||||
|
// always called with at least one block of data to process.
|
||||||
|
blockLoop:
|
||||||
|
round(R8)
|
||||||
|
round(R9)
|
||||||
|
round(R10)
|
||||||
|
round(R11)
|
||||||
|
|
||||||
|
CMPQ CX, BX
|
||||||
|
JLE blockLoop
|
||||||
|
|
||||||
|
// Copy vN back to d.
|
||||||
|
MOVQ R8, 0(AX)
|
||||||
|
MOVQ R9, 8(AX)
|
||||||
|
MOVQ R10, 16(AX)
|
||||||
|
MOVQ R11, 24(AX)
|
||||||
|
|
||||||
|
// The number of bytes written is CX minus the old base pointer.
|
||||||
|
SUBQ b_base+8(FP), CX
|
||||||
|
MOVQ CX, ret+32(FP)
|
||||||
|
|
||||||
|
RET
|
76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
Normal file
76
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// +build !amd64 appengine !gc purego
|
||||||
|
|
||||||
|
package xxhash
|
||||||
|
|
||||||
|
// Sum64 computes the 64-bit xxHash digest of b.
|
||||||
|
func Sum64(b []byte) uint64 {
|
||||||
|
// A simpler version would be
|
||||||
|
// d := New()
|
||||||
|
// d.Write(b)
|
||||||
|
// return d.Sum64()
|
||||||
|
// but this is faster, particularly for small inputs.
|
||||||
|
|
||||||
|
n := len(b)
|
||||||
|
var h uint64
|
||||||
|
|
||||||
|
if n >= 32 {
|
||||||
|
v1 := prime1v + prime2
|
||||||
|
v2 := prime2
|
||||||
|
v3 := uint64(0)
|
||||||
|
v4 := -prime1v
|
||||||
|
for len(b) >= 32 {
|
||||||
|
v1 = round(v1, u64(b[0:8:len(b)]))
|
||||||
|
v2 = round(v2, u64(b[8:16:len(b)]))
|
||||||
|
v3 = round(v3, u64(b[16:24:len(b)]))
|
||||||
|
v4 = round(v4, u64(b[24:32:len(b)]))
|
||||||
|
b = b[32:len(b):len(b)]
|
||||||
|
}
|
||||||
|
h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
|
||||||
|
h = mergeRound(h, v1)
|
||||||
|
h = mergeRound(h, v2)
|
||||||
|
h = mergeRound(h, v3)
|
||||||
|
h = mergeRound(h, v4)
|
||||||
|
} else {
|
||||||
|
h = prime5
|
||||||
|
}
|
||||||
|
|
||||||
|
h += uint64(n)
|
||||||
|
|
||||||
|
i, end := 0, len(b)
|
||||||
|
for ; i+8 <= end; i += 8 {
|
||||||
|
k1 := round(0, u64(b[i:i+8:len(b)]))
|
||||||
|
h ^= k1
|
||||||
|
h = rol27(h)*prime1 + prime4
|
||||||
|
}
|
||||||
|
if i+4 <= end {
|
||||||
|
h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
|
||||||
|
h = rol23(h)*prime2 + prime3
|
||||||
|
i += 4
|
||||||
|
}
|
||||||
|
for ; i < end; i++ {
|
||||||
|
h ^= uint64(b[i]) * prime5
|
||||||
|
h = rol11(h) * prime1
|
||||||
|
}
|
||||||
|
|
||||||
|
h ^= h >> 33
|
||||||
|
h *= prime2
|
||||||
|
h ^= h >> 29
|
||||||
|
h *= prime3
|
||||||
|
h ^= h >> 32
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeBlocks(d *Digest, b []byte) int {
|
||||||
|
v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
|
||||||
|
n := len(b)
|
||||||
|
for len(b) >= 32 {
|
||||||
|
v1 = round(v1, u64(b[0:8:len(b)]))
|
||||||
|
v2 = round(v2, u64(b[8:16:len(b)]))
|
||||||
|
v3 = round(v3, u64(b[16:24:len(b)]))
|
||||||
|
v4 = round(v4, u64(b[24:32:len(b)]))
|
||||||
|
b = b[32:len(b):len(b)]
|
||||||
|
}
|
||||||
|
d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
|
||||||
|
return n - len(b)
|
||||||
|
}
|
15
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
Normal file
15
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// +build appengine
|
||||||
|
|
||||||
|
// This file contains the safe implementations of otherwise unsafe-using code.
|
||||||
|
|
||||||
|
package xxhash
|
||||||
|
|
||||||
|
// Sum64String computes the 64-bit xxHash digest of s.
|
||||||
|
func Sum64String(s string) uint64 {
|
||||||
|
return Sum64([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteString adds more data to d. It always returns len(s), nil.
|
||||||
|
func (d *Digest) WriteString(s string) (n int, err error) {
|
||||||
|
return d.Write([]byte(s))
|
||||||
|
}
|
46
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
Normal file
46
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
// This file encapsulates usage of unsafe.
|
||||||
|
// xxhash_safe.go contains the safe implementations.
|
||||||
|
|
||||||
|
package xxhash
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Notes:
|
||||||
|
//
|
||||||
|
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
|
||||||
|
// for some discussion about these unsafe conversions.
|
||||||
|
//
|
||||||
|
// In the future it's possible that compiler optimizations will make these
|
||||||
|
// unsafe operations unnecessary: https://golang.org/issue/2205.
|
||||||
|
//
|
||||||
|
// Both of these wrapper functions still incur function call overhead since they
|
||||||
|
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
|
||||||
|
// for strings to squeeze out a bit more speed. Mid-stack inlining should
|
||||||
|
// eventually fix this.
|
||||||
|
|
||||||
|
// Sum64String computes the 64-bit xxHash digest of s.
|
||||||
|
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
||||||
|
func Sum64String(s string) uint64 {
|
||||||
|
var b []byte
|
||||||
|
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||||
|
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||||
|
bh.Len = len(s)
|
||||||
|
bh.Cap = len(s)
|
||||||
|
return Sum64(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteString adds more data to d. It always returns len(s), nil.
|
||||||
|
// It may be faster than Write([]byte(s)) by avoiding a copy.
|
||||||
|
func (d *Digest) WriteString(s string) (n int, err error) {
|
||||||
|
var b []byte
|
||||||
|
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||||||
|
bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
|
||||||
|
bh.Len = len(s)
|
||||||
|
bh.Cap = len(s)
|
||||||
|
return d.Write(b)
|
||||||
|
}
|
201
vendor/github.com/coredns/coredns/LICENSE
generated
vendored
Normal file
201
vendor/github.com/coredns/coredns/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2016-2020 The CoreDNS authors and contributors
|
||||||
|
|
||||||
|
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.
|
105
vendor/github.com/coredns/coredns/core/dnsserver/address.go
generated
vendored
Normal file
105
vendor/github.com/coredns/coredns/core/dnsserver/address.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type zoneAddr struct {
|
||||||
|
Zone string
|
||||||
|
Port string
|
||||||
|
Transport string // dns, tls or grpc
|
||||||
|
IPNet *net.IPNet // if reverse zone this hold the IPNet
|
||||||
|
Address string // used for bound zoneAddr - validation of overlapping
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the string representation of z.
|
||||||
|
func (z zoneAddr) String() string {
|
||||||
|
s := z.Transport + "://" + z.Zone + ":" + z.Port
|
||||||
|
if z.Address != "" {
|
||||||
|
s += " on " + z.Address
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeZone parses a zone string into a structured format with separate
|
||||||
|
// host, and port portions, as well as the original input string.
|
||||||
|
func normalizeZone(str string) (zoneAddr, error) {
|
||||||
|
trans, str := parse.Transport(str)
|
||||||
|
|
||||||
|
host, port, ipnet, err := plugin.SplitHostPort(str)
|
||||||
|
if err != nil {
|
||||||
|
return zoneAddr{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if port == "" {
|
||||||
|
switch trans {
|
||||||
|
case transport.DNS:
|
||||||
|
port = Port
|
||||||
|
case transport.TLS:
|
||||||
|
port = transport.TLSPort
|
||||||
|
case transport.GRPC:
|
||||||
|
port = transport.GRPCPort
|
||||||
|
case transport.HTTPS:
|
||||||
|
port = transport.HTTPSPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return zoneAddr{Zone: dns.Fqdn(host), Port: port, Transport: trans, IPNet: ipnet}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitProtocolHostPort splits a full formed address like "dns://[::1]:53" into parts.
|
||||||
|
func SplitProtocolHostPort(address string) (protocol string, ip string, port string, err error) {
|
||||||
|
parts := strings.Split(address, "://")
|
||||||
|
switch len(parts) {
|
||||||
|
case 1:
|
||||||
|
ip, port, err := net.SplitHostPort(parts[0])
|
||||||
|
return "", ip, port, err
|
||||||
|
case 2:
|
||||||
|
ip, port, err := net.SplitHostPort(parts[1])
|
||||||
|
return parts[0], ip, port, err
|
||||||
|
default:
|
||||||
|
return "", "", "", fmt.Errorf("provided value is not in an address format : %s", address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type zoneOverlap struct {
|
||||||
|
registeredAddr map[zoneAddr]zoneAddr // each zoneAddr is registered once by its key
|
||||||
|
unboundOverlap map[zoneAddr]zoneAddr // the "no bind" equiv ZoneAddr is registered by its original key
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOverlapZone() *zoneOverlap {
|
||||||
|
return &zoneOverlap{registeredAddr: make(map[zoneAddr]zoneAddr), unboundOverlap: make(map[zoneAddr]zoneAddr)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
func (zo *zoneOverlap) registerAndCheck(z zoneAddr) (existingZone *zoneAddr, overlappingZone *zoneAddr) {
|
||||||
|
|
||||||
|
if exist, ok := zo.registeredAddr[z]; ok {
|
||||||
|
// exact same zone already registered
|
||||||
|
return &exist, nil
|
||||||
|
}
|
||||||
|
uz := zoneAddr{Zone: z.Zone, Address: "", Port: z.Port, Transport: z.Transport}
|
||||||
|
if already, ok := zo.unboundOverlap[uz]; ok {
|
||||||
|
if z.Address == "" {
|
||||||
|
// current is not bound to an address, but there is already another zone with a bind address registered
|
||||||
|
return nil, &already
|
||||||
|
}
|
||||||
|
if _, ok := zo.registeredAddr[uz]; ok {
|
||||||
|
// current zone is bound to an address, but there is already an overlapping zone+port with no bind address
|
||||||
|
return nil, &uz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// there is no overlap, keep the current zoneAddr for future checks
|
||||||
|
zo.registeredAddr[z] = z
|
||||||
|
zo.unboundOverlap[uz] = z
|
||||||
|
return nil, nil
|
||||||
|
}
|
73
vendor/github.com/coredns/coredns/core/dnsserver/config.go
generated
vendored
Normal file
73
vendor/github.com/coredns/coredns/core/dnsserver/config.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config configuration for a single server.
|
||||||
|
type Config struct {
|
||||||
|
// The zone of the site.
|
||||||
|
Zone string
|
||||||
|
|
||||||
|
// one or several hostnames to bind the server to.
|
||||||
|
// defaults to a single empty string that denote the wildcard address
|
||||||
|
ListenHosts []string
|
||||||
|
|
||||||
|
// The port to listen on.
|
||||||
|
Port string
|
||||||
|
|
||||||
|
// Root points to a base directory we find user defined "things".
|
||||||
|
// First consumer is the file plugin to looks for zone files in this place.
|
||||||
|
Root string
|
||||||
|
|
||||||
|
// Debug controls the panic/recover mechanism that is enabled by default.
|
||||||
|
Debug bool
|
||||||
|
|
||||||
|
// The transport we implement, normally just "dns" over TCP/UDP, but could be
|
||||||
|
// DNS-over-TLS or DNS-over-gRPC.
|
||||||
|
Transport string
|
||||||
|
|
||||||
|
// If this function is not nil it will be used to further filter access
|
||||||
|
// to this handler. The primary use is to limit access to a reverse zone
|
||||||
|
// on a non-octet boundary, i.e. /17
|
||||||
|
FilterFunc func(string) bool
|
||||||
|
|
||||||
|
// TLSConfig when listening for encrypted connections (gRPC, DNS-over-TLS).
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
|
||||||
|
// Plugin stack.
|
||||||
|
Plugin []plugin.Plugin
|
||||||
|
|
||||||
|
// Compiled plugin stack.
|
||||||
|
pluginChain plugin.Handler
|
||||||
|
|
||||||
|
// Plugin interested in announcing that they exist, so other plugin can call methods
|
||||||
|
// on them should register themselves here. The name should be the name as return by the
|
||||||
|
// Handler's Name method.
|
||||||
|
registry map[string]plugin.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyForConfig build a key for identifying the configs during setup time
|
||||||
|
func keyForConfig(blocIndex int, blocKeyIndex int) string {
|
||||||
|
return fmt.Sprintf("%d:%d", blocIndex, blocKeyIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig gets the Config that corresponds to c.
|
||||||
|
// If none exist nil is returned.
|
||||||
|
func GetConfig(c *caddy.Controller) *Config {
|
||||||
|
ctx := c.Context().(*dnsContext)
|
||||||
|
key := keyForConfig(c.ServerBlockIndex, c.ServerBlockKeyIndex)
|
||||||
|
if cfg, ok := ctx.keysToConfigs[key]; ok {
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
// we should only get here during tests because directive
|
||||||
|
// actions typically skip the server blocks where we make
|
||||||
|
// the configs.
|
||||||
|
ctx.saveConfig(key, &Config{ListenHosts: []string{""}})
|
||||||
|
return GetConfig(c)
|
||||||
|
}
|
23
vendor/github.com/coredns/coredns/core/dnsserver/https.go
generated
vendored
Normal file
23
vendor/github.com/coredns/coredns/core/dnsserver/https.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/nonwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DoHWriter is a nonwriter.Writer that adds more specific LocalAddr and RemoteAddr methods.
|
||||||
|
type DoHWriter struct {
|
||||||
|
nonwriter.Writer
|
||||||
|
|
||||||
|
// raddr is the remote's address. This can be optionally set.
|
||||||
|
raddr net.Addr
|
||||||
|
// laddr is our address. This can be optionally set.
|
||||||
|
laddr net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteAddr returns the remote address.
|
||||||
|
func (d *DoHWriter) RemoteAddr() net.Addr { return d.raddr }
|
||||||
|
|
||||||
|
// LocalAddr returns the local address.
|
||||||
|
func (d *DoHWriter) LocalAddr() net.Addr { return d.laddr }
|
29
vendor/github.com/coredns/coredns/core/dnsserver/onstartup.go
generated
vendored
Normal file
29
vendor/github.com/coredns/coredns/core/dnsserver/onstartup.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// startUpZones create the text that we show when starting up:
|
||||||
|
// grpc://example.com.:1055
|
||||||
|
// example.com.:1053 on 127.0.0.1
|
||||||
|
func startUpZones(protocol, addr string, zones map[string]*Config) string {
|
||||||
|
s := ""
|
||||||
|
|
||||||
|
for zone := range zones {
|
||||||
|
// split addr into protocol, IP and Port
|
||||||
|
_, ip, port, err := SplitProtocolHostPort(addr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// this should not happen, but we need to take care of it anyway
|
||||||
|
s += fmt.Sprintln(protocol + zone + ":" + addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ip == "" {
|
||||||
|
s += fmt.Sprintln(protocol + zone + ":" + port)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if the server is listening on a specific address let's make it visible in the log,
|
||||||
|
// so one can differentiate between all active listeners
|
||||||
|
s += fmt.Sprintln(protocol + zone + ":" + port + " on " + ip)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
255
vendor/github.com/coredns/coredns/core/dnsserver/register.go
generated
vendored
Normal file
255
vendor/github.com/coredns/coredns/core/dnsserver/register.go
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
"github.com/caddyserver/caddy/caddyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
const serverType = "dns"
|
||||||
|
|
||||||
|
// Any flags defined here, need to be namespaced to the serverType other
|
||||||
|
// wise they potentially clash with other server types.
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&Port, serverType+".port", DefaultPort, "Default port")
|
||||||
|
|
||||||
|
caddy.RegisterServerType(serverType, caddy.ServerType{
|
||||||
|
Directives: func() []string { return Directives },
|
||||||
|
DefaultInput: func() caddy.Input {
|
||||||
|
return caddy.CaddyfileInput{
|
||||||
|
Filepath: "Corefile",
|
||||||
|
Contents: []byte(".:" + Port + " {\nwhoami\nlog\n}\n"),
|
||||||
|
ServerTypeName: serverType,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NewContext: newContext,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func newContext(i *caddy.Instance) caddy.Context {
|
||||||
|
return &dnsContext{keysToConfigs: make(map[string]*Config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type dnsContext struct {
|
||||||
|
keysToConfigs map[string]*Config
|
||||||
|
|
||||||
|
// configs is the master list of all site configs.
|
||||||
|
configs []*Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *dnsContext) saveConfig(key string, cfg *Config) {
|
||||||
|
h.configs = append(h.configs, cfg)
|
||||||
|
h.keysToConfigs[key] = cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile-time check to ensure dnsContext implements the caddy.Context interface
|
||||||
|
var _ caddy.Context = &dnsContext{}
|
||||||
|
|
||||||
|
// InspectServerBlocks make sure that everything checks out before
|
||||||
|
// executing directives and otherwise prepares the directives to
|
||||||
|
// be parsed and executed.
|
||||||
|
func (h *dnsContext) InspectServerBlocks(sourceFile string, serverBlocks []caddyfile.ServerBlock) ([]caddyfile.ServerBlock, error) {
|
||||||
|
// Normalize and check all the zone names and check for duplicates
|
||||||
|
for ib, s := range serverBlocks {
|
||||||
|
for ik, k := range s.Keys {
|
||||||
|
za, err := normalizeZone(k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.Keys[ik] = za.String()
|
||||||
|
// Save the config to our master list, and key it for lookups.
|
||||||
|
cfg := &Config{
|
||||||
|
Zone: za.Zone,
|
||||||
|
ListenHosts: []string{""},
|
||||||
|
Port: za.Port,
|
||||||
|
Transport: za.Transport,
|
||||||
|
}
|
||||||
|
keyConfig := keyForConfig(ib, ik)
|
||||||
|
if za.IPNet == nil {
|
||||||
|
h.saveConfig(keyConfig, cfg)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ones, bits := za.IPNet.Mask.Size()
|
||||||
|
if (bits-ones)%8 != 0 { // only do this for non-octet boundaries
|
||||||
|
cfg.FilterFunc = func(s string) bool {
|
||||||
|
// TODO(miek): strings.ToLower! Slow and allocates new string.
|
||||||
|
addr := dnsutil.ExtractAddressFromReverse(strings.ToLower(s))
|
||||||
|
if addr == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return za.IPNet.Contains(net.ParseIP(addr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.saveConfig(keyConfig, cfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serverBlocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeServers uses the newly-created siteConfigs to create and return a list of server instances.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// we must map (group) each config to a bind address
|
||||||
|
groups, err := groupConfigsByListenAddr(h.configs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// then we create a server for each group
|
||||||
|
var servers []caddy.Server
|
||||||
|
for addr, group := range groups {
|
||||||
|
// switch on addr
|
||||||
|
switch tr, _ := parse.Transport(addr); tr {
|
||||||
|
case transport.DNS:
|
||||||
|
s, err := NewServer(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
servers = append(servers, s)
|
||||||
|
|
||||||
|
case transport.TLS:
|
||||||
|
s, err := NewServerTLS(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
servers = append(servers, s)
|
||||||
|
|
||||||
|
case transport.GRPC:
|
||||||
|
s, err := NewServergRPC(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
servers = append(servers, s)
|
||||||
|
|
||||||
|
case transport.HTTPS:
|
||||||
|
s, err := NewServerHTTPS(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
servers = append(servers, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPlugin adds a plugin to a site's plugin stack.
|
||||||
|
func (c *Config) AddPlugin(m plugin.Plugin) {
|
||||||
|
c.Plugin = append(c.Plugin, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerHandler adds a handler to a site's handler registration. Handlers
|
||||||
|
// use this to announce that they exist to other plugin.
|
||||||
|
func (c *Config) registerHandler(h plugin.Handler) {
|
||||||
|
if c.registry == nil {
|
||||||
|
c.registry = make(map[string]plugin.Handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just overwrite...
|
||||||
|
c.registry[h.Name()] = h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler returns the plugin handler that has been added to the config under its name.
|
||||||
|
// This is useful to inspect if a certain plugin is active in this server.
|
||||||
|
// Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
|
||||||
|
// comes before the plugin you are checking; it will not be there (yet).
|
||||||
|
func (c *Config) Handler(name string) plugin.Handler {
|
||||||
|
if c.registry == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if h, ok := c.registry[name]; ok {
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handlers returns a slice of plugins that have been registered. This can be used to
|
||||||
|
// inspect and interact with registered plugins but cannot be used to remove or add plugins.
|
||||||
|
// Note that this is order dependent and the order is defined in directives.go, i.e. if your plugin
|
||||||
|
// comes before the plugin you are checking; it will not be there (yet).
|
||||||
|
func (c *Config) Handlers() []plugin.Handler {
|
||||||
|
if c.registry == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hs := make([]plugin.Handler, 0, len(c.registry))
|
||||||
|
for k := range c.registry {
|
||||||
|
hs = append(hs, c.registry[k])
|
||||||
|
}
|
||||||
|
return hs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *dnsContext) validateZonesAndListeningAddresses() error {
|
||||||
|
//Validate Zone and addresses
|
||||||
|
checker := newOverlapZone()
|
||||||
|
for _, conf := range h.configs {
|
||||||
|
for _, h := range conf.ListenHosts {
|
||||||
|
// Validate the overlapping of ZoneAddr
|
||||||
|
akey := zoneAddr{Transport: conf.Transport, Zone: conf.Zone, Address: h, Port: conf.Port}
|
||||||
|
existZone, overlapZone := checker.registerAndCheck(akey)
|
||||||
|
if existZone != nil {
|
||||||
|
return fmt.Errorf("cannot serve %s - it is already defined", akey.String())
|
||||||
|
}
|
||||||
|
if overlapZone != nil {
|
||||||
|
return fmt.Errorf("cannot serve %s - zone overlap listener capacity with %v", akey.String(), overlapZone.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// groupSiteConfigsByListenAddr groups site configs by their listen
|
||||||
|
// (bind) address, so sites that use the same listener can be served
|
||||||
|
// on the same server instance. The return value maps the listen
|
||||||
|
// address (what you pass into net.Listen) to the list of site configs.
|
||||||
|
// This function does NOT vet the configs to ensure they are compatible.
|
||||||
|
func groupConfigsByListenAddr(configs []*Config) (map[string][]*Config, error) {
|
||||||
|
|
||||||
|
groups := make(map[string][]*Config)
|
||||||
|
for _, conf := range configs {
|
||||||
|
for _, h := range conf.ListenHosts {
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(h, conf.Port))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addrstr := conf.Transport + "://" + addr.String()
|
||||||
|
groups[addrstr] = append(groups[addrstr], conf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultPort is the default port.
|
||||||
|
const DefaultPort = transport.Port
|
||||||
|
|
||||||
|
// These "soft defaults" are configurable by
|
||||||
|
// command line flags, etc.
|
||||||
|
var (
|
||||||
|
// Port is the port we listen on by default.
|
||||||
|
Port = DefaultPort
|
||||||
|
|
||||||
|
// GracefulTimeout is the maximum duration of a graceful shutdown.
|
||||||
|
GracefulTimeout time.Duration
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ caddy.GracefulServer = new(Server)
|
356
vendor/github.com/coredns/coredns/core/dnsserver/server.go
generated
vendored
Normal file
356
vendor/github.com/coredns/coredns/core/dnsserver/server.go
generated
vendored
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
// Package dnsserver implements all the interfaces from Caddy, so that CoreDNS can be a servertype plugin.
|
||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/edns"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/log"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/rcode"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/trace"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Server represents an instance of a server, which serves
|
||||||
|
// DNS requests at a particular address (host and port). A
|
||||||
|
// server is capable of serving numerous zones on
|
||||||
|
// the same address and the listener may be stopped for
|
||||||
|
// graceful termination (POSIX only).
|
||||||
|
type Server struct {
|
||||||
|
Addr string // Address we listen on
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
zones map[string]*Config // zones keyed by their address
|
||||||
|
dnsWg sync.WaitGroup // used to wait on outstanding connections
|
||||||
|
graceTimeout time.Duration // the maximum duration of a graceful shutdown
|
||||||
|
trace trace.Trace // the trace plugin for the server
|
||||||
|
debug bool // disable recover()
|
||||||
|
classChaos bool // allow non-INET class queries
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func NewServer(addr string, group []*Config) (*Server, error) {
|
||||||
|
|
||||||
|
s := &Server{
|
||||||
|
Addr: addr,
|
||||||
|
zones: make(map[string]*Config),
|
||||||
|
graceTimeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to bound our wg with one increment
|
||||||
|
// to prevent a "race condition" that is hard-coded
|
||||||
|
// into sync.WaitGroup.Wait() - basically, an add
|
||||||
|
// with a positive delta must be guaranteed to
|
||||||
|
// occur before Wait() is called on the wg.
|
||||||
|
// In a way, this kind of acts as a safety barrier.
|
||||||
|
s.dnsWg.Add(1)
|
||||||
|
|
||||||
|
for _, site := range group {
|
||||||
|
if site.Debug {
|
||||||
|
s.debug = true
|
||||||
|
log.D.Set()
|
||||||
|
} else {
|
||||||
|
// When reloading we need to explicitly disable debug logging if it is now disabled.
|
||||||
|
s.debug = false
|
||||||
|
log.D.Clear()
|
||||||
|
}
|
||||||
|
// set the config per zone
|
||||||
|
s.zones[site.Zone] = site
|
||||||
|
|
||||||
|
// compile custom plugin for everything
|
||||||
|
var stack plugin.Handler
|
||||||
|
for i := len(site.Plugin) - 1; i >= 0; i-- {
|
||||||
|
stack = site.Plugin[i](stack)
|
||||||
|
|
||||||
|
// register the *handler* also
|
||||||
|
site.registerHandler(stack)
|
||||||
|
|
||||||
|
if s.trace == nil && stack.Name() == "trace" {
|
||||||
|
// we have to stash away the plugin, not the
|
||||||
|
// Tracer object, because the Tracer won't be initialized yet
|
||||||
|
if t, ok := stack.(trace.Trace); ok {
|
||||||
|
s.trace = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Unblock CH class queries when any of these plugins are loaded.
|
||||||
|
if _, ok := EnableChaos[stack.Name()]; ok {
|
||||||
|
s.classChaos = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
site.pluginChain = stack
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||||
|
var _ caddy.GracefulServer = &Server{}
|
||||||
|
|
||||||
|
// Serve starts the server with an existing listener. It blocks until the server stops.
|
||||||
|
// This implements caddy.TCPServer interface.
|
||||||
|
func (s *Server) Serve(l net.Listener) error {
|
||||||
|
s.m.Lock()
|
||||||
|
s.server[tcp] = &dns.Server{Listener: l, Net: "tcp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
ctx := context.WithValue(context.Background(), Key{}, s)
|
||||||
|
s.ServeDNS(ctx, w, r)
|
||||||
|
})}
|
||||||
|
s.m.Unlock()
|
||||||
|
|
||||||
|
return s.server[tcp].ActivateAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServePacket starts the server with an existing packetconn. It blocks until the server stops.
|
||||||
|
// This implements caddy.UDPServer interface.
|
||||||
|
func (s *Server) ServePacket(p net.PacketConn) error {
|
||||||
|
s.m.Lock()
|
||||||
|
s.server[udp] = &dns.Server{PacketConn: p, Net: "udp", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
ctx := context.WithValue(context.Background(), Key{}, s)
|
||||||
|
s.ServeDNS(ctx, w, r)
|
||||||
|
})}
|
||||||
|
s.m.Unlock()
|
||||||
|
|
||||||
|
return s.server[udp].ActivateAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen implements caddy.TCPServer interface.
|
||||||
|
func (s *Server) Listen() (net.Listener, error) {
|
||||||
|
l, err := reuseport.Listen("tcp", s.Addr[len(transport.DNS+"://"):])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapListener Listen implements caddy.GracefulServer interface.
|
||||||
|
func (s *Server) WrapListener(ln net.Listener) net.Listener {
|
||||||
|
return ln
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenPacket implements caddy.UDPServer interface.
|
||||||
|
func (s *Server) ListenPacket() (net.PacketConn, error) {
|
||||||
|
p, err := reuseport.ListenPacket("udp", s.Addr[len(transport.DNS+"://"):])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the server. It blocks until the server is
|
||||||
|
// totally stopped. On POSIX systems, it will wait for
|
||||||
|
// connections to close (up to a max timeout of a few
|
||||||
|
// seconds); on Windows it will close the listener
|
||||||
|
// immediately.
|
||||||
|
// This implements Caddy.Stopper interface.
|
||||||
|
func (s *Server) Stop() (err error) {
|
||||||
|
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
// force connections to close after timeout
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
s.dnsWg.Done() // decrement our initial increment used as a barrier
|
||||||
|
s.dnsWg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for remaining connections to finish or
|
||||||
|
// force them all to close after timeout
|
||||||
|
select {
|
||||||
|
case <-time.After(s.graceTimeout):
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the listener now; this stops the server without delay
|
||||||
|
s.m.Lock()
|
||||||
|
for _, s1 := range s.server {
|
||||||
|
// We might not have started and initialized the full set of servers
|
||||||
|
if s1 != nil {
|
||||||
|
err = s1.Shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.m.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address together with Stop() implement caddy.GracefulServer.
|
||||||
|
func (s *Server) Address() string { return s.Addr }
|
||||||
|
|
||||||
|
// ServeDNS is the entry point for every request to the address that s
|
||||||
|
// is bound to. It acts as a multiplexer for the requests zonename as
|
||||||
|
// defined in the request so that the correct zone
|
||||||
|
// (configuration and plugin stack) will handle the request.
|
||||||
|
func (s *Server) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
// The default dns.Mux checks the question section size, but we have our
|
||||||
|
// own mux here. Check if we have a question section. If not drop them here.
|
||||||
|
if r == nil || len(r.Question) == 0 {
|
||||||
|
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.debug {
|
||||||
|
defer func() {
|
||||||
|
// In case the user doesn't enable error plugin, we still
|
||||||
|
// need to make sure that we stay alive up here
|
||||||
|
if rec := recover(); rec != nil {
|
||||||
|
log.Errorf("Recovered from panic in server: %q", s.Addr)
|
||||||
|
vars.Panic.Inc()
|
||||||
|
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeServerFailure)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !s.classChaos && r.Question[0].Qclass != dns.ClassINET {
|
||||||
|
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if m, err := edns.Version(r); err != nil { // Wrong EDNS version, return at once.
|
||||||
|
w.WriteMsg(m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap the response writer in a ScrubWriter so we automatically make the reply fit in the client's buffer.
|
||||||
|
w = request.NewScrubWriter(r, w)
|
||||||
|
|
||||||
|
q := strings.ToLower(r.Question[0].Name)
|
||||||
|
var (
|
||||||
|
off int
|
||||||
|
end bool
|
||||||
|
dshandler *Config
|
||||||
|
)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if h, ok := s.zones[q[off:]]; ok {
|
||||||
|
if r.Question[0].Qtype != dns.TypeDS {
|
||||||
|
if h.FilterFunc == nil {
|
||||||
|
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||||
|
if !plugin.ClientWrite(rcode) {
|
||||||
|
errorFunc(s.Addr, w, r, rcode)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// FilterFunc is set, call it to see if we should use this handler.
|
||||||
|
// This is given to full query name.
|
||||||
|
if h.FilterFunc(q) {
|
||||||
|
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||||
|
if !plugin.ClientWrite(rcode) {
|
||||||
|
errorFunc(s.Addr, w, r, rcode)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The type is DS, keep the handler, but keep on searching as maybe we are serving
|
||||||
|
// the parent as well and the DS should be routed to it - this will probably *misroute* DS
|
||||||
|
// queries to a possibly grand parent, but there is no way for us to know at this point
|
||||||
|
// if there is an actual delegation from grandparent -> parent -> zone.
|
||||||
|
// In all fairness: direct DS queries should not be needed.
|
||||||
|
dshandler = h
|
||||||
|
}
|
||||||
|
off, end = dns.NextLabel(q, off)
|
||||||
|
if end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Question[0].Qtype == dns.TypeDS && dshandler != nil && dshandler.pluginChain != nil {
|
||||||
|
// DS request, and we found a zone, use the handler for the query.
|
||||||
|
rcode, _ := dshandler.pluginChain.ServeDNS(ctx, w, r)
|
||||||
|
if !plugin.ClientWrite(rcode) {
|
||||||
|
errorFunc(s.Addr, w, r, rcode)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||||
|
if h, ok := s.zones["."]; ok && h.pluginChain != nil {
|
||||||
|
rcode, _ := h.pluginChain.ServeDNS(ctx, w, r)
|
||||||
|
if !plugin.ClientWrite(rcode) {
|
||||||
|
errorFunc(s.Addr, w, r, rcode)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Still here? Error out with REFUSED.
|
||||||
|
errorAndMetricsFunc(s.Addr, w, r, dns.RcodeRefused)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnStartupComplete lists the sites served by this server
|
||||||
|
// and any relevant information, assuming Quiet is false.
|
||||||
|
func (s *Server) OnStartupComplete() {
|
||||||
|
if Quiet {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := startUpZones("", s.Addr, s.zones)
|
||||||
|
if out != "" {
|
||||||
|
fmt.Print(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracer returns the tracer in the server if defined.
|
||||||
|
func (s *Server) Tracer() ot.Tracer {
|
||||||
|
if s.trace == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.trace.Tracer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// errorFunc responds to an DNS request with an error.
|
||||||
|
func errorFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int) {
|
||||||
|
state := request.Request{W: w, Req: r}
|
||||||
|
|
||||||
|
answer := new(dns.Msg)
|
||||||
|
answer.SetRcode(r, rc)
|
||||||
|
state.SizeAndDo(answer)
|
||||||
|
|
||||||
|
w.WriteMsg(answer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorAndMetricsFunc(server string, w dns.ResponseWriter, r *dns.Msg, rc int) {
|
||||||
|
state := request.Request{W: w, Req: r}
|
||||||
|
|
||||||
|
answer := new(dns.Msg)
|
||||||
|
answer.SetRcode(r, rc)
|
||||||
|
state.SizeAndDo(answer)
|
||||||
|
|
||||||
|
vars.Report(server, state, vars.Dropped, rcode.ToString(rc), answer.Len(), time.Now())
|
||||||
|
|
||||||
|
w.WriteMsg(answer)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
tcp = 0
|
||||||
|
udp = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key is the context key for the current server added to the context.
|
||||||
|
type Key struct{}
|
||||||
|
|
||||||
|
// EnableChaos is a map with plugin names for which we should open CH class queries as we block these by default.
|
||||||
|
var EnableChaos = map[string]struct{}{
|
||||||
|
"chaos": {},
|
||||||
|
"forward": {},
|
||||||
|
"proxy": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quiet mode will not show any informative output on initialization.
|
||||||
|
var Quiet bool
|
176
vendor/github.com/coredns/coredns/core/dnsserver/server_grpc.go
generated
vendored
Normal file
176
vendor/github.com/coredns/coredns/core/dnsserver/server_grpc.go
generated
vendored
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/pb"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"github.com/opentracing/opentracing-go"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServergRPC represents an instance of a DNS-over-gRPC server.
|
||||||
|
type ServergRPC struct {
|
||||||
|
*Server
|
||||||
|
grpcServer *grpc.Server
|
||||||
|
listenAddr net.Addr
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServergRPC returns a new CoreDNS GRPC server and compiles all plugin in to it.
|
||||||
|
func NewServergRPC(addr string, group []*Config) (*ServergRPC, error) {
|
||||||
|
s, err := NewServer(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// The *tls* plugin must make sure that multiple conflicting
|
||||||
|
// TLS configuration return an error: it can only be specified once.
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
for _, conf := range s.zones {
|
||||||
|
// Should we error if some configs *don't* have TLS?
|
||||||
|
tlsConfig = conf.TLSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ServergRPC{Server: s, tlsConfig: tlsConfig}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||||
|
var _ caddy.GracefulServer = &Server{}
|
||||||
|
|
||||||
|
// Serve implements caddy.TCPServer interface.
|
||||||
|
func (s *ServergRPC) Serve(l net.Listener) error {
|
||||||
|
s.m.Lock()
|
||||||
|
s.listenAddr = l.Addr()
|
||||||
|
s.m.Unlock()
|
||||||
|
|
||||||
|
if s.Tracer() != nil {
|
||||||
|
onlyIfParent := func(parentSpanCtx opentracing.SpanContext, method string, req, resp interface{}) bool {
|
||||||
|
return parentSpanCtx != nil
|
||||||
|
}
|
||||||
|
intercept := otgrpc.OpenTracingServerInterceptor(s.Tracer(), otgrpc.IncludingSpans(onlyIfParent))
|
||||||
|
s.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(intercept))
|
||||||
|
} else {
|
||||||
|
s.grpcServer = grpc.NewServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
pb.RegisterDnsServiceServer(s.grpcServer, s)
|
||||||
|
|
||||||
|
if s.tlsConfig != nil {
|
||||||
|
l = tls.NewListener(l, s.tlsConfig)
|
||||||
|
}
|
||||||
|
return s.grpcServer.Serve(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServePacket implements caddy.UDPServer interface.
|
||||||
|
func (s *ServergRPC) ServePacket(p net.PacketConn) error { return nil }
|
||||||
|
|
||||||
|
// Listen implements caddy.TCPServer interface.
|
||||||
|
func (s *ServergRPC) Listen() (net.Listener, error) {
|
||||||
|
|
||||||
|
l, err := reuseport.Listen("tcp", s.Addr[len(transport.GRPC+"://"):])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenPacket implements caddy.UDPServer interface.
|
||||||
|
func (s *ServergRPC) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||||
|
|
||||||
|
// OnStartupComplete lists the sites served by this server
|
||||||
|
// and any relevant information, assuming Quiet is false.
|
||||||
|
func (s *ServergRPC) OnStartupComplete() {
|
||||||
|
if Quiet {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := startUpZones(transport.GRPC+"://", s.Addr, s.zones)
|
||||||
|
if out != "" {
|
||||||
|
fmt.Print(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the server. It blocks until the server is
|
||||||
|
// totally stopped.
|
||||||
|
func (s *ServergRPC) Stop() (err error) {
|
||||||
|
s.m.Lock()
|
||||||
|
defer s.m.Unlock()
|
||||||
|
if s.grpcServer != nil {
|
||||||
|
s.grpcServer.GracefulStop()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query is the main entry-point into the gRPC server. From here we call ServeDNS like
|
||||||
|
// any normal server. We use a custom responseWriter to pick up the bytes we need to write
|
||||||
|
// back to the client as a protobuf.
|
||||||
|
func (s *ServergRPC) Query(ctx context.Context, in *pb.DnsPacket) (*pb.DnsPacket, error) {
|
||||||
|
msg := new(dns.Msg)
|
||||||
|
err := msg.Unpack(in.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, ok := peer.FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("no peer in gRPC context")
|
||||||
|
}
|
||||||
|
|
||||||
|
a, ok := p.Addr.(*net.TCPAddr)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("no TCP peer in gRPC context: %v", p.Addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := &gRPCresponse{localAddr: s.listenAddr, remoteAddr: a, Msg: msg}
|
||||||
|
|
||||||
|
dnsCtx := context.WithValue(ctx, Key{}, s.Server)
|
||||||
|
s.ServeDNS(dnsCtx, w, msg)
|
||||||
|
|
||||||
|
packed, err := w.Msg.Pack()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.DnsPacket{Msg: packed}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown stops the server (non gracefully).
|
||||||
|
func (s *ServergRPC) Shutdown() error {
|
||||||
|
if s.grpcServer != nil {
|
||||||
|
s.grpcServer.Stop()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type gRPCresponse struct {
|
||||||
|
localAddr net.Addr
|
||||||
|
remoteAddr net.Addr
|
||||||
|
Msg *dns.Msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is the hack that makes this work. It does not actually write the message
|
||||||
|
// but returns the bytes we need to write in r. We can then pick this up in Query
|
||||||
|
// and write a proper protobuf back to the client.
|
||||||
|
func (r *gRPCresponse) Write(b []byte) (int, error) {
|
||||||
|
r.Msg = new(dns.Msg)
|
||||||
|
return len(b), r.Msg.Unpack(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These methods implement the dns.ResponseWriter interface from Go DNS.
|
||||||
|
func (r *gRPCresponse) Close() error { return nil }
|
||||||
|
func (r *gRPCresponse) TsigStatus() error { return nil }
|
||||||
|
func (r *gRPCresponse) TsigTimersOnly(b bool) {}
|
||||||
|
func (r *gRPCresponse) Hijack() {}
|
||||||
|
func (r *gRPCresponse) LocalAddr() net.Addr { return r.localAddr }
|
||||||
|
func (r *gRPCresponse) RemoteAddr() net.Addr { return r.remoteAddr }
|
||||||
|
func (r *gRPCresponse) WriteMsg(m *dns.Msg) error { r.Msg = m; return nil }
|
155
vendor/github.com/coredns/coredns/core/dnsserver/server_https.go
generated
vendored
Normal file
155
vendor/github.com/coredns/coredns/core/dnsserver/server_https.go
generated
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/doh"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/response"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServerHTTPS represents an instance of a DNS-over-HTTPS server.
|
||||||
|
type ServerHTTPS struct {
|
||||||
|
*Server
|
||||||
|
httpsServer *http.Server
|
||||||
|
listenAddr net.Addr
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServerHTTPS returns a new CoreDNS GRPC server and compiles all plugins in to it.
|
||||||
|
func NewServerHTTPS(addr string, group []*Config) (*ServerHTTPS, error) {
|
||||||
|
s, err := NewServer(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// The *tls* plugin must make sure that multiple conflicting
|
||||||
|
// TLS configuration return an error: it can only be specified once.
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
for _, conf := range s.zones {
|
||||||
|
// Should we error if some configs *don't* have TLS?
|
||||||
|
tlsConfig = conf.TLSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
sh := &ServerHTTPS{Server: s, tlsConfig: tlsConfig, httpsServer: new(http.Server)}
|
||||||
|
sh.httpsServer.Handler = sh
|
||||||
|
|
||||||
|
return sh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||||
|
var _ caddy.GracefulServer = &Server{}
|
||||||
|
|
||||||
|
// Serve implements caddy.TCPServer interface.
|
||||||
|
func (s *ServerHTTPS) Serve(l net.Listener) error {
|
||||||
|
s.m.Lock()
|
||||||
|
s.listenAddr = l.Addr()
|
||||||
|
s.m.Unlock()
|
||||||
|
|
||||||
|
if s.tlsConfig != nil {
|
||||||
|
l = tls.NewListener(l, s.tlsConfig)
|
||||||
|
}
|
||||||
|
return s.httpsServer.Serve(l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServePacket implements caddy.UDPServer interface.
|
||||||
|
func (s *ServerHTTPS) ServePacket(p net.PacketConn) error { return nil }
|
||||||
|
|
||||||
|
// Listen implements caddy.TCPServer interface.
|
||||||
|
func (s *ServerHTTPS) Listen() (net.Listener, error) {
|
||||||
|
|
||||||
|
l, err := reuseport.Listen("tcp", s.Addr[len(transport.HTTPS+"://"):])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenPacket implements caddy.UDPServer interface.
|
||||||
|
func (s *ServerHTTPS) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||||
|
|
||||||
|
// OnStartupComplete lists the sites served by this server
|
||||||
|
// and any relevant information, assuming Quiet is false.
|
||||||
|
func (s *ServerHTTPS) OnStartupComplete() {
|
||||||
|
if Quiet {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := startUpZones(transport.HTTPS+"://", s.Addr, s.zones)
|
||||||
|
if out != "" {
|
||||||
|
fmt.Print(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop stops the server. It blocks until the server is totally stopped.
|
||||||
|
func (s *ServerHTTPS) Stop() error {
|
||||||
|
s.m.Lock()
|
||||||
|
defer s.m.Unlock()
|
||||||
|
if s.httpsServer != nil {
|
||||||
|
s.httpsServer.Shutdown(context.Background())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
func (s *ServerHTTPS) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
if r.URL.Path != doh.Path {
|
||||||
|
http.Error(w, "", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, err := doh.RequestToMsg(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a DoHWriter with the correct addresses in it.
|
||||||
|
h, p, _ := net.SplitHostPort(r.RemoteAddr)
|
||||||
|
port, _ := strconv.Atoi(p)
|
||||||
|
dw := &DoHWriter{laddr: s.listenAddr, raddr: &net.TCPAddr{IP: net.ParseIP(h), Port: port}}
|
||||||
|
|
||||||
|
// We just call the normal chain handler - all error handling is done there.
|
||||||
|
// We should expect a packet to be returned that we can send to the client.
|
||||||
|
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
||||||
|
s.ServeDNS(ctx, dw, msg)
|
||||||
|
|
||||||
|
// See section 4.2.1 of RFC 8484.
|
||||||
|
// We are using code 500 to indicate an unexpected situation when the chain
|
||||||
|
// handler has not provided any response message.
|
||||||
|
if dw.Msg == nil {
|
||||||
|
http.Error(w, "No response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, _ := dw.Msg.Pack()
|
||||||
|
|
||||||
|
mt, _ := response.Typify(dw.Msg, time.Now().UTC())
|
||||||
|
age := dnsutil.MinimalTTL(dw.Msg, mt)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", doh.MimeType)
|
||||||
|
w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%f", age.Seconds()))
|
||||||
|
w.Header().Set("Content-Length", strconv.Itoa(len(buf)))
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
|
||||||
|
w.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown stops the server (non gracefully).
|
||||||
|
func (s *ServerHTTPS) Shutdown() error {
|
||||||
|
if s.httpsServer != nil {
|
||||||
|
s.httpsServer.Shutdown(context.Background())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
86
vendor/github.com/coredns/coredns/core/dnsserver/server_tls.go
generated
vendored
Normal file
86
vendor/github.com/coredns/coredns/core/dnsserver/server_tls.go
generated
vendored
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package dnsserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServerTLS represents an instance of a TLS-over-DNS-server.
|
||||||
|
type ServerTLS struct {
|
||||||
|
*Server
|
||||||
|
tlsConfig *tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServerTLS returns a new CoreDNS TLS server and compiles all plugin in to it.
|
||||||
|
func NewServerTLS(addr string, group []*Config) (*ServerTLS, error) {
|
||||||
|
s, err := NewServer(addr, group)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// The *tls* plugin must make sure that multiple conflicting
|
||||||
|
// TLS configuration return an error: it can only be specified once.
|
||||||
|
var tlsConfig *tls.Config
|
||||||
|
for _, conf := range s.zones {
|
||||||
|
// Should we error if some configs *don't* have TLS?
|
||||||
|
tlsConfig = conf.TLSConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ServerTLS{Server: s, tlsConfig: tlsConfig}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile-time check to ensure Server implements the caddy.GracefulServer interface
|
||||||
|
var _ caddy.GracefulServer = &Server{}
|
||||||
|
|
||||||
|
// Serve implements caddy.TCPServer interface.
|
||||||
|
func (s *ServerTLS) Serve(l net.Listener) error {
|
||||||
|
s.m.Lock()
|
||||||
|
|
||||||
|
if s.tlsConfig != nil {
|
||||||
|
l = tls.NewListener(l, s.tlsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only fill out the TCP server for this one.
|
||||||
|
s.server[tcp] = &dns.Server{Listener: l, Net: "tcp-tls", Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
|
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
||||||
|
s.ServeDNS(ctx, w, r)
|
||||||
|
})}
|
||||||
|
s.m.Unlock()
|
||||||
|
|
||||||
|
return s.server[tcp].ActivateAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServePacket implements caddy.UDPServer interface.
|
||||||
|
func (s *ServerTLS) ServePacket(p net.PacketConn) error { return nil }
|
||||||
|
|
||||||
|
// Listen implements caddy.TCPServer interface.
|
||||||
|
func (s *ServerTLS) Listen() (net.Listener, error) {
|
||||||
|
l, err := reuseport.Listen("tcp", s.Addr[len(transport.TLS+"://"):])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenPacket implements caddy.UDPServer interface.
|
||||||
|
func (s *ServerTLS) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
||||||
|
|
||||||
|
// OnStartupComplete lists the sites served by this server
|
||||||
|
// and any relevant information, assuming Quiet is false.
|
||||||
|
func (s *ServerTLS) OnStartupComplete() {
|
||||||
|
if Quiet {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := startUpZones(transport.TLS+"://", s.Addr, s.zones)
|
||||||
|
if out != "" {
|
||||||
|
fmt.Print(out)
|
||||||
|
}
|
||||||
|
}
|
58
vendor/github.com/coredns/coredns/core/dnsserver/zdirectives.go
generated
vendored
Normal file
58
vendor/github.com/coredns/coredns/core/dnsserver/zdirectives.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// generated by directives_generate.go; DO NOT EDIT
|
||||||
|
|
||||||
|
package dnsserver
|
||||||
|
|
||||||
|
// Directives are registered in the order they should be
|
||||||
|
// executed.
|
||||||
|
//
|
||||||
|
// Ordering is VERY important. Every plugin will
|
||||||
|
// feel the effects of all other plugin below
|
||||||
|
// (after) them during a request, but they must not
|
||||||
|
// care what plugin above them are doing.
|
||||||
|
var Directives = []string{
|
||||||
|
"metadata",
|
||||||
|
"cancel",
|
||||||
|
"tls",
|
||||||
|
"reload",
|
||||||
|
"nsid",
|
||||||
|
"bufsize",
|
||||||
|
"root",
|
||||||
|
"bind",
|
||||||
|
"debug",
|
||||||
|
"trace",
|
||||||
|
"ready",
|
||||||
|
"health",
|
||||||
|
"pprof",
|
||||||
|
"prometheus",
|
||||||
|
"errors",
|
||||||
|
"log",
|
||||||
|
"dnstap",
|
||||||
|
"acl",
|
||||||
|
"any",
|
||||||
|
"chaos",
|
||||||
|
"loadbalance",
|
||||||
|
"cache",
|
||||||
|
"rewrite",
|
||||||
|
"dnssec",
|
||||||
|
"autopath",
|
||||||
|
"template",
|
||||||
|
"transfer",
|
||||||
|
"hosts",
|
||||||
|
"route53",
|
||||||
|
"azure",
|
||||||
|
"clouddns",
|
||||||
|
"federation",
|
||||||
|
"k8s_external",
|
||||||
|
"kubernetes",
|
||||||
|
"file",
|
||||||
|
"auto",
|
||||||
|
"secondary",
|
||||||
|
"etcd",
|
||||||
|
"loop",
|
||||||
|
"forward",
|
||||||
|
"grpc",
|
||||||
|
"erratic",
|
||||||
|
"whoami",
|
||||||
|
"on",
|
||||||
|
"sign",
|
||||||
|
}
|
213
vendor/github.com/coredns/coredns/coremain/run.go
generated
vendored
Normal file
213
vendor/github.com/coredns/coredns/coremain/run.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
// Package coremain contains the functions for starting CoreDNS.
|
||||||
|
package coremain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy.DefaultConfigFile = "Corefile"
|
||||||
|
caddy.Quiet = true // don't show init stuff from caddy
|
||||||
|
setVersion()
|
||||||
|
|
||||||
|
flag.StringVar(&conf, "conf", "", "Corefile to load (default \""+caddy.DefaultConfigFile+"\")")
|
||||||
|
flag.BoolVar(&plugins, "plugins", false, "List installed plugins")
|
||||||
|
flag.StringVar(&caddy.PidFile, "pidfile", "", "Path to write pid file")
|
||||||
|
flag.BoolVar(&version, "version", false, "Show version")
|
||||||
|
flag.BoolVar(&dnsserver.Quiet, "quiet", false, "Quiet mode (no initialization output)")
|
||||||
|
|
||||||
|
caddy.RegisterCaddyfileLoader("flag", caddy.LoaderFunc(confLoader))
|
||||||
|
caddy.SetDefaultCaddyfileLoader("default", caddy.LoaderFunc(defaultLoader))
|
||||||
|
|
||||||
|
caddy.AppName = coreName
|
||||||
|
caddy.AppVersion = CoreVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run is CoreDNS's main() function.
|
||||||
|
func Run() {
|
||||||
|
caddy.TrapSignals()
|
||||||
|
|
||||||
|
// Reset flag.CommandLine to get rid of unwanted flags for instance from glog (used in kubernetes).
|
||||||
|
// And read the ones we want to keep.
|
||||||
|
flag.VisitAll(func(f *flag.Flag) {
|
||||||
|
if _, ok := flagsBlacklist[f.Name]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
flagsToKeep = append(flagsToKeep, f)
|
||||||
|
})
|
||||||
|
|
||||||
|
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||||
|
for _, f := range flagsToKeep {
|
||||||
|
flag.Var(f.Value, f.Name, f.Usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(flag.Args()) > 0 {
|
||||||
|
mustLogFatal(fmt.Errorf("extra command line arguments: %s", flag.Args()))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetOutput(os.Stdout)
|
||||||
|
log.SetFlags(0) // Set to 0 because we're doing our own time, with timezone
|
||||||
|
|
||||||
|
if version {
|
||||||
|
showVersion()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
if plugins {
|
||||||
|
fmt.Println(caddy.DescribePlugins())
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Corefile input
|
||||||
|
corefile, err := caddy.LoadCaddyfile(serverType)
|
||||||
|
if err != nil {
|
||||||
|
mustLogFatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start your engines
|
||||||
|
instance, err := caddy.Start(corefile)
|
||||||
|
if err != nil {
|
||||||
|
mustLogFatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !dnsserver.Quiet {
|
||||||
|
showVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Twiddle your thumbs
|
||||||
|
instance.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
// mustLogFatal wraps log.Fatal() in a way that ensures the
|
||||||
|
// output is always printed to stderr so the user can see it
|
||||||
|
// if the user is still there, even if the process log was not
|
||||||
|
// enabled. If this process is an upgrade, however, and the user
|
||||||
|
// might not be there anymore, this just logs to the process
|
||||||
|
// log and exits.
|
||||||
|
func mustLogFatal(args ...interface{}) {
|
||||||
|
if !caddy.IsUpgrade() {
|
||||||
|
log.SetOutput(os.Stderr)
|
||||||
|
}
|
||||||
|
log.Fatal(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// confLoader loads the Caddyfile using the -conf flag.
|
||||||
|
func confLoader(serverType string) (caddy.Input, error) {
|
||||||
|
if conf == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if conf == "stdin" {
|
||||||
|
return caddy.CaddyfileFromPipe(os.Stdin, serverType)
|
||||||
|
}
|
||||||
|
|
||||||
|
contents, err := ioutil.ReadFile(conf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return caddy.CaddyfileInput{
|
||||||
|
Contents: contents,
|
||||||
|
Filepath: conf,
|
||||||
|
ServerTypeName: serverType,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultLoader loads the Corefile from the current working directory.
|
||||||
|
func defaultLoader(serverType string) (caddy.Input, error) {
|
||||||
|
contents, err := ioutil.ReadFile(caddy.DefaultConfigFile)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return caddy.CaddyfileInput{
|
||||||
|
Contents: contents,
|
||||||
|
Filepath: caddy.DefaultConfigFile,
|
||||||
|
ServerTypeName: serverType,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// showVersion prints the version that is starting.
|
||||||
|
func showVersion() {
|
||||||
|
fmt.Print(versionString())
|
||||||
|
fmt.Print(releaseString())
|
||||||
|
if devBuild && gitShortStat != "" {
|
||||||
|
fmt.Printf("%s\n%s\n", gitShortStat, gitFilesModified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// versionString returns the CoreDNS version as a string.
|
||||||
|
func versionString() string {
|
||||||
|
return fmt.Sprintf("%s-%s\n", caddy.AppName, caddy.AppVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// releaseString returns the release information related to CoreDNS version:
|
||||||
|
// <OS>/<ARCH>, <go version>, <commit>
|
||||||
|
// e.g.,
|
||||||
|
// linux/amd64, go1.8.3, a6d2d7b5
|
||||||
|
func releaseString() string {
|
||||||
|
return fmt.Sprintf("%s/%s, %s, %s\n", runtime.GOOS, runtime.GOARCH, runtime.Version(), GitCommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setVersion figures out the version information
|
||||||
|
// based on variables set by -ldflags.
|
||||||
|
func setVersion() {
|
||||||
|
// A development build is one that's not at a tag or has uncommitted changes
|
||||||
|
devBuild = gitTag == "" || gitShortStat != ""
|
||||||
|
|
||||||
|
// Only set the appVersion if -ldflags was used
|
||||||
|
if gitNearestTag != "" || gitTag != "" {
|
||||||
|
if devBuild && gitNearestTag != "" {
|
||||||
|
appVersion = fmt.Sprintf("%s (+%s %s)", strings.TrimPrefix(gitNearestTag, "v"), GitCommit, buildDate)
|
||||||
|
} else if gitTag != "" {
|
||||||
|
appVersion = strings.TrimPrefix(gitTag, "v")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flags that control program flow or startup
|
||||||
|
var (
|
||||||
|
conf string
|
||||||
|
version bool
|
||||||
|
plugins bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// Build information obtained with the help of -ldflags
|
||||||
|
var (
|
||||||
|
appVersion = "(untracked dev build)" // inferred at startup
|
||||||
|
devBuild = true // inferred at startup
|
||||||
|
|
||||||
|
buildDate string // date -u
|
||||||
|
gitTag string // git describe --exact-match HEAD 2> /dev/null
|
||||||
|
gitNearestTag string // git describe --abbrev=0 --tags HEAD
|
||||||
|
gitShortStat string // git diff-index --shortstat
|
||||||
|
gitFilesModified string // git diff-index --name-only HEAD
|
||||||
|
|
||||||
|
// Gitcommit contains the commit where we built CoreDNS from.
|
||||||
|
GitCommit string
|
||||||
|
)
|
||||||
|
|
||||||
|
// flagsBlacklist removes flags with these names from our flagset.
|
||||||
|
var flagsBlacklist = map[string]struct{}{
|
||||||
|
"logtostderr": {},
|
||||||
|
"alsologtostderr": {},
|
||||||
|
"v": {},
|
||||||
|
"stderrthreshold": {},
|
||||||
|
"vmodule": {},
|
||||||
|
"log_backtrace_at": {},
|
||||||
|
"log_dir": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
var flagsToKeep []*flag.Flag
|
8
vendor/github.com/coredns/coredns/coremain/version.go
generated
vendored
Normal file
8
vendor/github.com/coredns/coredns/coremain/version.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package coremain
|
||||||
|
|
||||||
|
// Various CoreDNS constants.
|
||||||
|
const (
|
||||||
|
CoreVersion = "1.6.9"
|
||||||
|
coreName = "CoreDNS"
|
||||||
|
serverType = "dns"
|
||||||
|
)
|
13
vendor/github.com/coredns/coredns/pb/Makefile
generated
vendored
Normal file
13
vendor/github.com/coredns/coredns/pb/Makefile
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Generate the Go files from the dns.proto protobuf, you need the utilities
|
||||||
|
# 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
|
||||||
|
# to run this generation step.
|
||||||
|
|
||||||
|
all: dns.pb.go
|
||||||
|
|
||||||
|
dns.pb.go: dns.proto
|
||||||
|
protoc --go_out=plugins=grpc:. dns.proto
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm dns.pb.go
|
156
vendor/github.com/coredns/coredns/pb/dns.pb.go
generated
vendored
Normal file
156
vendor/github.com/coredns/coredns/pb/dns.pb.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: dns.proto
|
||||||
|
|
||||||
|
package pb
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
fmt "fmt"
|
||||||
|
math "math"
|
||||||
|
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
|
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 (m *DnsPacket) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*DnsPacket) ProtoMessage() {}
|
||||||
|
func (*DnsPacket) Descriptor() ([]byte, []int) {
|
||||||
|
return fileDescriptor_638ff8d8aaf3d8ae, []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DnsPacket) XXX_Unmarshal(b []byte) error {
|
||||||
|
return xxx_messageInfo_DnsPacket.Unmarshal(m, b)
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*DnsPacket)(nil), "coredns.dns.DnsPacket")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("dns.proto", fileDescriptor_638ff8d8aaf3d8ae) }
|
||||||
|
|
||||||
|
var fileDescriptor_638ff8d8aaf3d8ae = []byte{
|
||||||
|
// 120 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4c, 0xc9, 0x2b, 0xd6,
|
||||||
|
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,
|
||||||
|
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 _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// DnsServiceClient is the client API for DnsService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||||
|
type DnsServiceClient interface {
|
||||||
|
Query(ctx context.Context, in *DnsPacket, opts ...grpc.CallOption) (*DnsPacket, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dnsServiceClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDnsServiceClient(cc *grpc.ClientConn) 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.
|
||||||
|
type DnsServiceServer interface {
|
||||||
|
Query(context.Context, *DnsPacket) (*DnsPacket, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterDnsServiceServer(s *grpc.Server, 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
}
|
12
vendor/github.com/coredns/coredns/pb/dns.proto
generated
vendored
Normal file
12
vendor/github.com/coredns/coredns/pb/dns.proto
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package coredns.dns;
|
||||||
|
option go_package = "pb";
|
||||||
|
|
||||||
|
message DnsPacket {
|
||||||
|
bytes msg = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service DnsService {
|
||||||
|
rpc Query (DnsPacket) returns (DnsPacket);
|
||||||
|
}
|
49
vendor/github.com/coredns/coredns/plugin/backend.go
generated
vendored
Normal file
49
vendor/github.com/coredns/coredns/plugin/backend.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/etcd/msg"
|
||||||
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServiceBackend defines a (dynamic) backend that returns a slice of service definitions.
|
||||||
|
type ServiceBackend interface {
|
||||||
|
// Services communicates with the backend to retrieve the service definitions. Exact indicates
|
||||||
|
// on exact match should be returned.
|
||||||
|
Services(ctx context.Context, state request.Request, exact bool, opt Options) ([]msg.Service, error)
|
||||||
|
|
||||||
|
// Reverse communicates with the backend to retrieve service definition based on a IP address
|
||||||
|
// instead of a name. I.e. a reverse DNS lookup.
|
||||||
|
Reverse(ctx context.Context, state request.Request, exact bool, opt Options) ([]msg.Service, error)
|
||||||
|
|
||||||
|
// Lookup is used to find records else where.
|
||||||
|
Lookup(ctx context.Context, state request.Request, name string, typ uint16) (*dns.Msg, error)
|
||||||
|
|
||||||
|
// Returns _all_ services that matches a certain name.
|
||||||
|
// Note: it does not implement a specific service.
|
||||||
|
Records(ctx context.Context, state request.Request, exact bool) ([]msg.Service, error)
|
||||||
|
|
||||||
|
// IsNameError return true if err indicated a record not found condition
|
||||||
|
IsNameError(err error) bool
|
||||||
|
|
||||||
|
Transferer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transferer defines an interface for backends that provide AXFR of all records.
|
||||||
|
type Transferer interface {
|
||||||
|
// Serial returns a SOA serial number to construct a SOA record.
|
||||||
|
Serial(state request.Request) uint32
|
||||||
|
|
||||||
|
// MinTTL returns the minimum TTL to be used in the SOA record.
|
||||||
|
MinTTL(state request.Request) uint32
|
||||||
|
|
||||||
|
// Transfer handles a zone transfer it writes to the client just
|
||||||
|
// like any other handler.
|
||||||
|
Transfer(ctx context.Context, state request.Request) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options are extra options that can be specified for a lookup.
|
||||||
|
type Options struct{}
|
549
vendor/github.com/coredns/coredns/plugin/backend_lookup.go
generated
vendored
Normal file
549
vendor/github.com/coredns/coredns/plugin/backend_lookup.go
generated
vendored
Normal file
@ -0,0 +1,549 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/etcd/msg"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
services, err := checkForApex(ctx, b, zone, state, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dup := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, serv := range services {
|
||||||
|
|
||||||
|
what, ip := serv.HostType()
|
||||||
|
|
||||||
|
switch what {
|
||||||
|
case dns.TypeCNAME:
|
||||||
|
if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
|
||||||
|
// x CNAME x is a direct loop, don't add those
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newRecord := serv.NewCNAME(state.QName(), serv.Host)
|
||||||
|
if len(previousRecords) > 7 {
|
||||||
|
// don't add it, and just continue
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dnsutil.DuplicateCNAME(newRecord, previousRecords) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
|
||||||
|
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||||
|
state1.Zone = zone
|
||||||
|
nextRecords, err := A(ctx, b, zone, state1, append(previousRecords, newRecord), opt)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||||
|
if len(nextRecords) > 0 {
|
||||||
|
records = append(records, newRecord)
|
||||||
|
records = append(records, nextRecords...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// This means we can not complete the CNAME, try to look else where.
|
||||||
|
target := newRecord.Target
|
||||||
|
// Lookup
|
||||||
|
m1, e1 := b.Lookup(ctx, state, target, state.QType())
|
||||||
|
if e1 != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Len(m1.Answer) > 0 here is well?
|
||||||
|
records = append(records, newRecord)
|
||||||
|
records = append(records, m1.Answer...)
|
||||||
|
continue
|
||||||
|
|
||||||
|
case dns.TypeA:
|
||||||
|
if _, ok := dup[serv.Host]; !ok {
|
||||||
|
dup[serv.Host] = struct{}{}
|
||||||
|
records = append(records, serv.NewA(state.QName(), ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
case dns.TypeAAAA:
|
||||||
|
// nada
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
services, err := checkForApex(ctx, b, zone, state, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dup := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, serv := range services {
|
||||||
|
|
||||||
|
what, ip := serv.HostType()
|
||||||
|
|
||||||
|
switch what {
|
||||||
|
case dns.TypeCNAME:
|
||||||
|
// 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)) {
|
||||||
|
// x CNAME x is a direct loop, don't add those
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newRecord := serv.NewCNAME(state.QName(), serv.Host)
|
||||||
|
if len(previousRecords) > 7 {
|
||||||
|
// don't add it, and just continue
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dnsutil.DuplicateCNAME(newRecord, previousRecords) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
|
||||||
|
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||||
|
state1.Zone = zone
|
||||||
|
nextRecords, err := AAAA(ctx, b, zone, state1, append(previousRecords, newRecord), opt)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||||
|
if len(nextRecords) > 0 {
|
||||||
|
records = append(records, newRecord)
|
||||||
|
records = append(records, nextRecords...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// This means we can not complete the CNAME, try to look else where.
|
||||||
|
target := newRecord.Target
|
||||||
|
m1, e1 := b.Lookup(ctx, state, target, state.QType())
|
||||||
|
if e1 != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Len(m1.Answer) > 0 here is well?
|
||||||
|
records = append(records, newRecord)
|
||||||
|
records = append(records, m1.Answer...)
|
||||||
|
continue
|
||||||
|
// both here again
|
||||||
|
|
||||||
|
case dns.TypeA:
|
||||||
|
// nada
|
||||||
|
|
||||||
|
case dns.TypeAAAA:
|
||||||
|
if _, ok := dup[serv.Host]; !ok {
|
||||||
|
dup[serv.Host] = struct{}{}
|
||||||
|
records = append(records, serv.NewAAAA(state.QName(), ip))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SRV returns SRV records from the Backend.
|
||||||
|
// If the Target is not a name but an IP address, a name is created on the fly.
|
||||||
|
func SRV(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) (records, extra []dns.RR, err error) {
|
||||||
|
services, err := b.Services(ctx, state, false, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dup := make(map[item]struct{})
|
||||||
|
lookup := make(map[string]struct{})
|
||||||
|
|
||||||
|
// Looping twice to get the right weight vs priority. This might break because we may drop duplicate SRV records latter on.
|
||||||
|
w := make(map[int]int)
|
||||||
|
for _, serv := range services {
|
||||||
|
weight := 100
|
||||||
|
if serv.Weight != 0 {
|
||||||
|
weight = serv.Weight
|
||||||
|
}
|
||||||
|
if _, ok := w[serv.Priority]; !ok {
|
||||||
|
w[serv.Priority] = weight
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
w[serv.Priority] += weight
|
||||||
|
}
|
||||||
|
for _, serv := range services {
|
||||||
|
// Don't add the entry if the port is -1 (invalid). The kubernetes plugin uses port -1 when a service/endpoint
|
||||||
|
// does not have any declared ports.
|
||||||
|
if serv.Port == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
w1 := 100.0 / float64(w[serv.Priority])
|
||||||
|
if serv.Weight == 0 {
|
||||||
|
w1 *= 100
|
||||||
|
} else {
|
||||||
|
w1 *= float64(serv.Weight)
|
||||||
|
}
|
||||||
|
weight := uint16(math.Floor(w1))
|
||||||
|
|
||||||
|
what, ip := serv.HostType()
|
||||||
|
|
||||||
|
switch what {
|
||||||
|
case dns.TypeCNAME:
|
||||||
|
srv := serv.NewSRV(state.QName(), weight)
|
||||||
|
records = append(records, srv)
|
||||||
|
|
||||||
|
if _, ok := lookup[srv.Target]; ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup[srv.Target] = struct{}{}
|
||||||
|
|
||||||
|
if !dns.IsSubDomain(zone, srv.Target) {
|
||||||
|
m1, e1 := b.Lookup(ctx, state, srv.Target, dns.TypeA)
|
||||||
|
if e1 == nil {
|
||||||
|
extra = append(extra, m1.Answer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
m1, e1 = b.Lookup(ctx, state, srv.Target, dns.TypeAAAA)
|
||||||
|
if e1 == nil {
|
||||||
|
// If we have seen CNAME's we *assume* that they are already added.
|
||||||
|
for _, a := range m1.Answer {
|
||||||
|
if _, ok := a.(*dns.CNAME); !ok {
|
||||||
|
extra = append(extra, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// 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.
|
||||||
|
state1 := state.NewWithQuestion(srv.Target, dns.TypeA)
|
||||||
|
addr, e1 := A(ctx, b, zone, state1, nil, opt)
|
||||||
|
if e1 == nil {
|
||||||
|
extra = append(extra, addr...)
|
||||||
|
}
|
||||||
|
// TODO(miek): AAAA as well here.
|
||||||
|
|
||||||
|
case dns.TypeA, dns.TypeAAAA:
|
||||||
|
addr := serv.Host
|
||||||
|
serv.Host = msg.Domain(serv.Key)
|
||||||
|
srv := serv.NewSRV(state.QName(), weight)
|
||||||
|
|
||||||
|
if ok := isDuplicate(dup, srv.Target, "", srv.Port); !ok {
|
||||||
|
records = append(records, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok := isDuplicate(dup, srv.Target, addr, 0); !ok {
|
||||||
|
extra = append(extra, newAddress(serv, srv.Target, ip, what))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, extra, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MX returns MX records from the Backend. If the Target is not a name but an IP address, a name is created on the fly.
|
||||||
|
func MX(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) (records, extra []dns.RR, err error) {
|
||||||
|
services, err := b.Services(ctx, state, false, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dup := make(map[item]struct{})
|
||||||
|
lookup := make(map[string]struct{})
|
||||||
|
for _, serv := range services {
|
||||||
|
if !serv.Mail {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
what, ip := serv.HostType()
|
||||||
|
switch what {
|
||||||
|
case dns.TypeCNAME:
|
||||||
|
mx := serv.NewMX(state.QName())
|
||||||
|
records = append(records, mx)
|
||||||
|
if _, ok := lookup[mx.Mx]; ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup[mx.Mx] = struct{}{}
|
||||||
|
|
||||||
|
if !dns.IsSubDomain(zone, mx.Mx) {
|
||||||
|
m1, e1 := b.Lookup(ctx, state, mx.Mx, dns.TypeA)
|
||||||
|
if e1 == nil {
|
||||||
|
extra = append(extra, m1.Answer...)
|
||||||
|
}
|
||||||
|
|
||||||
|
m1, e1 = b.Lookup(ctx, state, mx.Mx, dns.TypeAAAA)
|
||||||
|
if e1 == nil {
|
||||||
|
// If we have seen CNAME's we *assume* that they are already added.
|
||||||
|
for _, a := range m1.Answer {
|
||||||
|
if _, ok := a.(*dns.CNAME); !ok {
|
||||||
|
extra = append(extra, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Internal name
|
||||||
|
state1 := state.NewWithQuestion(mx.Mx, dns.TypeA)
|
||||||
|
addr, e1 := A(ctx, b, zone, state1, nil, opt)
|
||||||
|
if e1 == nil {
|
||||||
|
extra = append(extra, addr...)
|
||||||
|
}
|
||||||
|
// TODO(miek): AAAA as well here.
|
||||||
|
|
||||||
|
case dns.TypeA, dns.TypeAAAA:
|
||||||
|
addr := serv.Host
|
||||||
|
serv.Host = msg.Domain(serv.Key)
|
||||||
|
mx := serv.NewMX(state.QName())
|
||||||
|
|
||||||
|
if ok := isDuplicate(dup, mx.Mx, "", mx.Preference); !ok {
|
||||||
|
records = append(records, mx)
|
||||||
|
}
|
||||||
|
// Fake port to be 0 for address...
|
||||||
|
if ok := isDuplicate(dup, serv.Host, addr, 0); !ok {
|
||||||
|
extra = append(extra, newAddress(serv, serv.Host, ip, what))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, extra, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CNAME returns CNAME records from the backend or an error.
|
||||||
|
func CNAME(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) (records []dns.RR, err error) {
|
||||||
|
services, err := b.Services(ctx, state, true, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(services) > 0 {
|
||||||
|
serv := services[0]
|
||||||
|
if ip := net.ParseIP(serv.Host); ip == nil {
|
||||||
|
records = append(records, serv.NewCNAME(state.QName(), serv.Host))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
|
||||||
|
services, err := b.Services(ctx, state, true, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dup := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, serv := range services {
|
||||||
|
|
||||||
|
what, _ := serv.HostType()
|
||||||
|
|
||||||
|
switch what {
|
||||||
|
case dns.TypeCNAME:
|
||||||
|
if Name(state.Name()).Matches(dns.Fqdn(serv.Host)) {
|
||||||
|
// x CNAME x is a direct loop, don't add those
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newRecord := serv.NewCNAME(state.QName(), serv.Host)
|
||||||
|
if len(previousRecords) > 7 {
|
||||||
|
// don't add it, and just continue
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dnsutil.DuplicateCNAME(newRecord, previousRecords) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dns.IsSubDomain(zone, dns.Fqdn(serv.Host)) {
|
||||||
|
state1 := state.NewWithQuestion(serv.Host, state.QType())
|
||||||
|
state1.Zone = zone
|
||||||
|
nextRecords, err := TXT(ctx, b, zone, state1, append(previousRecords, newRecord), opt)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// Not only have we found something we should add the CNAME and the IP addresses.
|
||||||
|
if len(nextRecords) > 0 {
|
||||||
|
records = append(records, newRecord)
|
||||||
|
records = append(records, nextRecords...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// This means we can not complete the CNAME, try to look else where.
|
||||||
|
target := newRecord.Target
|
||||||
|
// Lookup
|
||||||
|
m1, e1 := b.Lookup(ctx, state, target, state.QType())
|
||||||
|
if e1 != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Len(m1.Answer) > 0 here is well?
|
||||||
|
records = append(records, newRecord)
|
||||||
|
records = append(records, m1.Answer...)
|
||||||
|
continue
|
||||||
|
|
||||||
|
case dns.TypeTXT:
|
||||||
|
if _, ok := dup[serv.Host]; !ok {
|
||||||
|
dup[serv.Host] = struct{}{}
|
||||||
|
return append(records, serv.NewTXT(state.QName())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PTR returns the PTR records from the backend, only services that have a domain name as host are included.
|
||||||
|
func PTR(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) (records []dns.RR, err error) {
|
||||||
|
services, err := b.Reverse(ctx, state, true, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dup := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, serv := range services {
|
||||||
|
if ip := net.ParseIP(serv.Host); ip == nil {
|
||||||
|
if _, ok := dup[serv.Host]; !ok {
|
||||||
|
dup[serv.Host] = struct{}{}
|
||||||
|
records = append(records, serv.NewPTR(state.QName(), serv.Host))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NS returns NS records from the backend
|
||||||
|
func NS(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) (records, extra []dns.RR, err error) {
|
||||||
|
// NS record for this zone live in a special place, ns.dns.<zone>. Fake our lookup.
|
||||||
|
// only a tad bit fishy...
|
||||||
|
old := state.QName()
|
||||||
|
|
||||||
|
state.Clear()
|
||||||
|
state.Req.Question[0].Name = "ns.dns." + zone
|
||||||
|
services, err := b.Services(ctx, state, false, opt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
// ... and reset
|
||||||
|
state.Req.Question[0].Name = old
|
||||||
|
|
||||||
|
seen := map[string]bool{}
|
||||||
|
|
||||||
|
for _, serv := range services {
|
||||||
|
what, ip := serv.HostType()
|
||||||
|
switch what {
|
||||||
|
case dns.TypeCNAME:
|
||||||
|
return nil, nil, fmt.Errorf("NS record must be an IP address: %s", serv.Host)
|
||||||
|
|
||||||
|
case dns.TypeA, dns.TypeAAAA:
|
||||||
|
serv.Host = msg.Domain(serv.Key)
|
||||||
|
extra = append(extra, newAddress(serv, serv.Host, ip, what))
|
||||||
|
ns := serv.NewNS(state.QName())
|
||||||
|
if _, ok := seen[ns.Ns]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[ns.Ns] = true
|
||||||
|
records = append(records, ns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return records, extra, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOA returns a SOA record from the backend.
|
||||||
|
func SOA(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) ([]dns.RR, error) {
|
||||||
|
minTTL := b.MinTTL(state)
|
||||||
|
ttl := uint32(300)
|
||||||
|
if minTTL < ttl {
|
||||||
|
ttl = minTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
header := dns.RR_Header{Name: zone, Rrtype: dns.TypeSOA, Ttl: ttl, Class: dns.ClassINET}
|
||||||
|
|
||||||
|
Mbox := hostmaster + "."
|
||||||
|
Ns := "ns.dns."
|
||||||
|
if zone[0] != '.' {
|
||||||
|
Mbox += zone
|
||||||
|
Ns += zone
|
||||||
|
}
|
||||||
|
|
||||||
|
soa := &dns.SOA{Hdr: header,
|
||||||
|
Mbox: Mbox,
|
||||||
|
Ns: Ns,
|
||||||
|
Serial: b.Serial(state),
|
||||||
|
Refresh: 7200,
|
||||||
|
Retry: 1800,
|
||||||
|
Expire: 86400,
|
||||||
|
Minttl: minTTL,
|
||||||
|
}
|
||||||
|
return []dns.RR{soa}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackendError writes an error response to the client.
|
||||||
|
func BackendError(ctx context.Context, b ServiceBackend, zone string, rcode int, state request.Request, err error, opt Options) (int, error) {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetRcode(state.Req, rcode)
|
||||||
|
m.Authoritative = true
|
||||||
|
m.Ns, _ = SOA(ctx, b, zone, state, opt)
|
||||||
|
|
||||||
|
state.W.WriteMsg(m)
|
||||||
|
// Return success as the rcode to signal we have written to the client.
|
||||||
|
return dns.RcodeSuccess, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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}
|
||||||
|
|
||||||
|
if what == dns.TypeA {
|
||||||
|
return &dns.A{Hdr: hdr, A: ip}
|
||||||
|
}
|
||||||
|
// Should always be dns.TypeAAAA
|
||||||
|
return &dns.AAAA{Hdr: hdr, AAAA: ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkForApex checks the special apex.dns directory for records that will be returned as A or AAAA.
|
||||||
|
func checkForApex(ctx context.Context, b ServiceBackend, zone string, state request.Request, opt Options) ([]msg.Service, error) {
|
||||||
|
if state.Name() != zone {
|
||||||
|
return b.Services(ctx, state, false, opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the zone name itself is queried we fake the query to search for a special entry
|
||||||
|
// this is equivalent to the NS search code.
|
||||||
|
old := state.QName()
|
||||||
|
state.Clear()
|
||||||
|
state.Req.Question[0].Name = dnsutil.Join("apex.dns", zone)
|
||||||
|
|
||||||
|
services, err := b.Services(ctx, state, false, opt)
|
||||||
|
if err == nil {
|
||||||
|
state.Req.Question[0].Name = old
|
||||||
|
return services, err
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Req.Question[0].Name = old
|
||||||
|
return b.Services(ctx, state, false, opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// item holds records.
|
||||||
|
type item struct {
|
||||||
|
name string // name of the record (either owner or something else unique).
|
||||||
|
port uint16 // port of the record (used for address records, A and AAAA).
|
||||||
|
addr string // address of the record (A and AAAA).
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDuplicate uses m to see if the combo (name, addr, port) already exists. If it does
|
||||||
|
// not exist already IsDuplicate will also add the record to the map.
|
||||||
|
func isDuplicate(m map[item]struct{}, name, addr string, port uint16) bool {
|
||||||
|
if addr != "" {
|
||||||
|
_, ok := m[item{name, 0, addr}]
|
||||||
|
if !ok {
|
||||||
|
m[item{name, 0, addr}] = struct{}{}
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
_, ok := m[item{name, port, ""}]
|
||||||
|
if !ok {
|
||||||
|
m[item{name, port, ""}] = struct{}{}
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostmaster = "hostmaster"
|
13
vendor/github.com/coredns/coredns/plugin/done.go
generated
vendored
Normal file
13
vendor/github.com/coredns/coredns/plugin/done.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Done is a non-blocking function that returns true if the context has been canceled.
|
||||||
|
func Done(ctx context.Context) bool {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
48
vendor/github.com/coredns/coredns/plugin/etcd/msg/path.go
generated
vendored
Normal file
48
vendor/github.com/coredns/coredns/plugin/etcd/msg/path.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package msg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnsutil"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Path converts a domainname to an etcd path. If s looks like service.staging.skydns.local.,
|
||||||
|
// the resulting key will be /skydns/local/skydns/staging/service .
|
||||||
|
func Path(s, prefix string) string {
|
||||||
|
l := dns.SplitDomainName(s)
|
||||||
|
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
||||||
|
return path.Join(append([]string{"/" + prefix + "/"}, l...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain is the opposite of Path.
|
||||||
|
func Domain(s string) string {
|
||||||
|
l := strings.Split(s, "/")
|
||||||
|
// start with 1, to strip /skydns
|
||||||
|
for i, j := 1, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
||||||
|
return dnsutil.Join(l[1 : len(l)-1]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PathWithWildcard acts as Path, but if a name contains wildcards (* or any), the name will be
|
||||||
|
// chopped of before the (first) wildcard, and we do a higher level search and
|
||||||
|
// later find the matching names. So service.*.skydns.local, will look for all
|
||||||
|
// services under skydns.local and will later check for names that match
|
||||||
|
// service.*.skydns.local. If a wildcard is found the returned bool is true.
|
||||||
|
func PathWithWildcard(s, prefix string) (string, bool) {
|
||||||
|
l := dns.SplitDomainName(s)
|
||||||
|
for i, j := 0, len(l)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
l[i], l[j] = l[j], l[i]
|
||||||
|
}
|
||||||
|
for i, k := range l {
|
||||||
|
if k == "*" || k == "any" {
|
||||||
|
return path.Join(append([]string{"/" + prefix + "/"}, l[:i]...)...), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path.Join(append([]string{"/" + prefix + "/"}, l...)...), false
|
||||||
|
}
|
177
vendor/github.com/coredns/coredns/plugin/etcd/msg/service.go
generated
vendored
Normal file
177
vendor/github.com/coredns/coredns/plugin/etcd/msg/service.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// Package msg defines the Service structure which is used for service discovery.
|
||||||
|
package msg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Service defines a discoverable service in etcd. It is the rdata from a SRV
|
||||||
|
// record, but with a twist. Host (Target in SRV) must be a domain name, but
|
||||||
|
// if it looks like an IP address (4/6), we will treat it like an IP address.
|
||||||
|
type Service struct {
|
||||||
|
Host string `json:"host,omitempty"`
|
||||||
|
Port int `json:"port,omitempty"`
|
||||||
|
Priority int `json:"priority,omitempty"`
|
||||||
|
Weight int `json:"weight,omitempty"`
|
||||||
|
Text string `json:"text,omitempty"`
|
||||||
|
Mail bool `json:"mail,omitempty"` // Be an MX record. Priority becomes Preference.
|
||||||
|
TTL uint32 `json:"ttl,omitempty"`
|
||||||
|
|
||||||
|
// When a SRV record with a "Host: IP-address" is added, we synthesize
|
||||||
|
// a srv.Target domain name. Normally we convert the full Key where
|
||||||
|
// the record lives to a DNS name and use this as the srv.Target. When
|
||||||
|
// TargetStrip > 0 we strip the left most TargetStrip labels from the
|
||||||
|
// DNS name.
|
||||||
|
TargetStrip int `json:"targetstrip,omitempty"`
|
||||||
|
|
||||||
|
// Group is used to group (or *not* to group) different services
|
||||||
|
// together. Services with an identical Group are returned in the same
|
||||||
|
// answer.
|
||||||
|
Group string `json:"group,omitempty"`
|
||||||
|
|
||||||
|
// Etcd key where we found this service and ignored from json un-/marshalling
|
||||||
|
Key string `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSRV returns a new SRV record based on the Service.
|
||||||
|
func (s *Service) NewSRV(name string, weight uint16) *dns.SRV {
|
||||||
|
host := dns.Fqdn(s.Host)
|
||||||
|
if s.TargetStrip > 0 {
|
||||||
|
host = targetStrip(host, s.TargetStrip)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dns.SRV{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: s.TTL},
|
||||||
|
Priority: uint16(s.Priority), Weight: weight, Port: uint16(s.Port), Target: host}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMX returns a new MX record based on the Service.
|
||||||
|
func (s *Service) NewMX(name string) *dns.MX {
|
||||||
|
host := dns.Fqdn(s.Host)
|
||||||
|
if s.TargetStrip > 0 {
|
||||||
|
host = targetStrip(host, s.TargetStrip)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dns.MX{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: s.TTL},
|
||||||
|
Preference: uint16(s.Priority), Mx: host}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewA returns a new A record based on the Service.
|
||||||
|
func (s *Service) NewA(name string, ip net.IP) *dns.A {
|
||||||
|
return &dns.A{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: s.TTL}, A: ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAAAA returns a new AAAA record based on the Service.
|
||||||
|
func (s *Service) NewAAAA(name string, ip net.IP) *dns.AAAA {
|
||||||
|
return &dns.AAAA{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: s.TTL}, AAAA: ip}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCNAME returns a new CNAME record based on the Service.
|
||||||
|
func (s *Service) NewCNAME(name string, target string) *dns.CNAME {
|
||||||
|
return &dns.CNAME{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: s.TTL}, Target: dns.Fqdn(target)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTXT returns a new TXT record based on the Service.
|
||||||
|
func (s *Service) NewTXT(name string) *dns.TXT {
|
||||||
|
return &dns.TXT{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: s.TTL}, Txt: split255(s.Text)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPTR returns a new PTR record based on the Service.
|
||||||
|
func (s *Service) NewPTR(name string, target string) *dns.PTR {
|
||||||
|
return &dns.PTR{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: s.TTL}, Ptr: dns.Fqdn(target)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNS returns a new NS record based on the Service.
|
||||||
|
func (s *Service) NewNS(name string) *dns.NS {
|
||||||
|
host := dns.Fqdn(s.Host)
|
||||||
|
if s.TargetStrip > 0 {
|
||||||
|
host = targetStrip(host, s.TargetStrip)
|
||||||
|
}
|
||||||
|
return &dns.NS{Hdr: dns.RR_Header{Name: name, Rrtype: dns.TypeNS, Class: dns.ClassINET, Ttl: s.TTL}, Ns: host}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group checks the services in sx, it looks for a Group attribute on the shortest
|
||||||
|
// keys. If there are multiple shortest keys *and* the group attribute disagrees (and
|
||||||
|
// is not empty), we don't consider it a group.
|
||||||
|
// If a group is found, only services with *that* group (or no group) will be returned.
|
||||||
|
func Group(sx []Service) []Service {
|
||||||
|
if len(sx) == 0 {
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shortest key with group attribute sets the group for this set.
|
||||||
|
group := sx[0].Group
|
||||||
|
slashes := strings.Count(sx[0].Key, "/")
|
||||||
|
length := make([]int, len(sx))
|
||||||
|
for i, s := range sx {
|
||||||
|
x := strings.Count(s.Key, "/")
|
||||||
|
length[i] = x
|
||||||
|
if x < slashes {
|
||||||
|
if s.Group == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
slashes = x
|
||||||
|
group = s.Group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if group == "" {
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := []Service{} // with slice-tricks in sx we can prolly save this allocation (TODO)
|
||||||
|
|
||||||
|
for i, s := range sx {
|
||||||
|
if s.Group == "" {
|
||||||
|
ret = append(ret, s)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disagreement on the same level
|
||||||
|
if length[i] == slashes && s.Group != group {
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Group == group {
|
||||||
|
ret = append(ret, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split255 splits a string into 255 byte chunks.
|
||||||
|
func split255(s string) []string {
|
||||||
|
if len(s) < 255 {
|
||||||
|
return []string{s}
|
||||||
|
}
|
||||||
|
sx := []string{}
|
||||||
|
p, i := 0, 255
|
||||||
|
for {
|
||||||
|
if i <= len(s) {
|
||||||
|
sx = append(sx, s[p:i])
|
||||||
|
} else {
|
||||||
|
sx = append(sx, s[p:])
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
p, i = p+255, i+255
|
||||||
|
}
|
||||||
|
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetStrip strips "targetstrip" labels from the left side of the fully qualified name.
|
||||||
|
func targetStrip(name string, targetStrip int) string {
|
||||||
|
offset, end := 0, false
|
||||||
|
for i := 0; i < targetStrip; i++ {
|
||||||
|
offset, end = dns.NextLabel(name, offset)
|
||||||
|
}
|
||||||
|
if end {
|
||||||
|
// We overshot the name, use the original one.
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
name = name[offset:]
|
||||||
|
return name
|
||||||
|
}
|
37
vendor/github.com/coredns/coredns/plugin/etcd/msg/type.go
generated
vendored
Normal file
37
vendor/github.com/coredns/coredns/plugin/etcd/msg/type.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package msg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HostType returns the DNS type of what is encoded in the Service Host field. We're reusing
|
||||||
|
// dns.TypeXXX to not reinvent a new set of identifiers.
|
||||||
|
//
|
||||||
|
// dns.TypeA: the service's Host field contains an A record.
|
||||||
|
// dns.TypeAAAA: the service's Host field contains an AAAA record.
|
||||||
|
// dns.TypeCNAME: the service's Host field contains a name.
|
||||||
|
//
|
||||||
|
// Note that a service can double/triple as a TXT record or MX record.
|
||||||
|
func (s *Service) HostType() (what uint16, normalized net.IP) {
|
||||||
|
|
||||||
|
ip := net.ParseIP(s.Host)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
|
||||||
|
case ip == nil:
|
||||||
|
if len(s.Text) == 0 {
|
||||||
|
return dns.TypeCNAME, nil
|
||||||
|
}
|
||||||
|
return dns.TypeTXT, nil
|
||||||
|
|
||||||
|
case ip.To4() != nil:
|
||||||
|
return dns.TypeA, ip.To4()
|
||||||
|
|
||||||
|
case ip.To4() == nil:
|
||||||
|
return dns.TypeAAAA, ip.To16()
|
||||||
|
}
|
||||||
|
// This should never be reached.
|
||||||
|
return dns.TypeNone, nil
|
||||||
|
}
|
79
vendor/github.com/coredns/coredns/plugin/metrics/README.md
generated
vendored
Normal file
79
vendor/github.com/coredns/coredns/plugin/metrics/README.md
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# prometheus
|
||||||
|
|
||||||
|
## Name
|
||||||
|
|
||||||
|
*prometheus* - enables [Prometheus](https://prometheus.io/) metrics.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
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 following metrics are exported:
|
||||||
|
|
||||||
|
* `coredns_build_info{version, revision, goversion}` - info about CoreDNS itself.
|
||||||
|
* `coredns_panic_count_total{}` - total number of panics.
|
||||||
|
* `coredns_dns_request_count_total{server, zone, proto, family}` - total query count.
|
||||||
|
* `coredns_dns_request_duration_seconds{server, zone, type}` - duration to process each query.
|
||||||
|
* `coredns_dns_request_size_bytes{server, zone, proto}` - size of the request in bytes.
|
||||||
|
* `coredns_dns_request_do_count_total{server, zone}` - queries that have the DO bit set
|
||||||
|
* `coredns_dns_request_type_count_total{server, zone, type}` - counter of queries per zone and type.
|
||||||
|
* `coredns_dns_response_size_bytes{server, zone, proto}` - response size in bytes.
|
||||||
|
* `coredns_dns_response_rcode_count_total{server, zone, rcode}` - response per zone and rcode.
|
||||||
|
* `coredns_plugin_enabled{server, zone, name}` - indicates whether a plugin is enabled on per server and zone basis.
|
||||||
|
|
||||||
|
Each counter has a label `zone` which is the zonename used for the request/response.
|
||||||
|
|
||||||
|
Extra labels used are:
|
||||||
|
|
||||||
|
* `server` is identifying the server responsible for the request. This is a string formatted
|
||||||
|
as the server's listening address: `<scheme>://[<bind>]:<port>`. I.e. for a "normal" DNS server
|
||||||
|
this is `dns://:53`. If you are using the *bind* plugin an IP address is included, e.g.: `dns://127.0.0.53:53`.
|
||||||
|
* `proto` which holds the transport of the response ("udp" or "tcp")
|
||||||
|
* The address family (`family`) of the transport (1 = IP (IP version 4), 2 = IP6 (IP version 6)).
|
||||||
|
* `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, IXFR, AXFR and ANY) and "other" which lumps together all
|
||||||
|
other types.
|
||||||
|
* The `response_rcode_count_total` has an extra label `rcode` which holds the rcode of the response.
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
This plugin can only be used once per Server Block.
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
~~~
|
||||||
|
prometheus [ADDRESS]
|
||||||
|
~~~
|
||||||
|
|
||||||
|
For each zone that you want to see metrics for.
|
||||||
|
|
||||||
|
It optionally takes a bind address to which the metrics are exported; the default
|
||||||
|
listens on `localhost:9153`. The metrics path is fixed to `/metrics`.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Use an alternative listening address:
|
||||||
|
|
||||||
|
~~~ corefile
|
||||||
|
. {
|
||||||
|
prometheus localhost:9253
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Or via an environment variable (this is supported throughout the Corefile): `export PORT=9253`, and
|
||||||
|
then:
|
||||||
|
|
||||||
|
~~~ corefile
|
||||||
|
. {
|
||||||
|
prometheus localhost:{$PORT}
|
||||||
|
}
|
||||||
|
~~~
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
When reloading, the Prometheus handler is stopped before the new server instance is started.
|
||||||
|
If that new server fails to start, then the initial server instance is still available and DNS queries still served,
|
||||||
|
but Prometheus handler stays down.
|
||||||
|
Prometheus will not reply HTTP request until a successful reload or a complete restart of CoreDNS.
|
||||||
|
Only the plugins that register as Handler are visible in `coredns_plugin_enabled{server, zone, name}`. As of today the plugins reload and bind will not be reported.
|
24
vendor/github.com/coredns/coredns/plugin/metrics/context.go
generated
vendored
Normal file
24
vendor/github.com/coredns/coredns/plugin/metrics/context.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithServer returns the current server handling the request. It returns the
|
||||||
|
// server listening address: <scheme>://[<bind>]:<port> Normally this is
|
||||||
|
// something like "dns://:53", but if the bind plugin is used, i.e. "bind
|
||||||
|
// 127.0.0.53", it will be "dns://127.0.0.53:53", etc. If not address is found
|
||||||
|
// the empty string is returned.
|
||||||
|
//
|
||||||
|
// Basic usage with a metric:
|
||||||
|
//
|
||||||
|
// <metric>.WithLabelValues(metrics.WithServer(ctx), labels..).Add(1)
|
||||||
|
func WithServer(ctx context.Context) string {
|
||||||
|
srv := ctx.Value(dnsserver.Key{})
|
||||||
|
if srv == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return srv.(*dnsserver.Server).Addr
|
||||||
|
}
|
35
vendor/github.com/coredns/coredns/plugin/metrics/handler.go
generated
vendored
Normal file
35
vendor/github.com/coredns/coredns/plugin/metrics/handler.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/rcode"
|
||||||
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServeDNS implements the Handler interface.
|
||||||
|
func (m *Metrics) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||||
|
state := request.Request{W: w, Req: r}
|
||||||
|
|
||||||
|
qname := state.QName()
|
||||||
|
zone := plugin.Zones(m.ZoneNames()).Matches(qname)
|
||||||
|
if zone == "" {
|
||||||
|
zone = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record response to get status code and size of the reply.
|
||||||
|
rw := dnstest.NewRecorder(w)
|
||||||
|
status, err := plugin.NextOrFailure(m.Name(), m.Next, ctx, rw, r)
|
||||||
|
|
||||||
|
vars.Report(WithServer(ctx), state, zone, rcode.ToString(rw.Rcode), rw.Len, rw.Start)
|
||||||
|
|
||||||
|
return status, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements the Handler interface.
|
||||||
|
func (m *Metrics) Name() string { return "prometheus" }
|
170
vendor/github.com/coredns/coredns/plugin/metrics/metrics.go
generated
vendored
Normal file
170
vendor/github.com/coredns/coredns/plugin/metrics/metrics.go
generated
vendored
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
// Package metrics implement a handler and plugin that provides Prometheus metrics.
|
||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Metrics holds the prometheus configuration. The metrics' path is fixed to be /metrics .
|
||||||
|
type Metrics struct {
|
||||||
|
Next plugin.Handler
|
||||||
|
Addr string
|
||||||
|
Reg *prometheus.Registry
|
||||||
|
|
||||||
|
ln net.Listener
|
||||||
|
lnSetup bool
|
||||||
|
|
||||||
|
mux *http.ServeMux
|
||||||
|
srv *http.Server
|
||||||
|
|
||||||
|
zoneNames []string
|
||||||
|
zoneMap map[string]struct{}
|
||||||
|
zoneMu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new instance of Metrics with the given address.
|
||||||
|
func New(addr string) *Metrics {
|
||||||
|
met := &Metrics{
|
||||||
|
Addr: addr,
|
||||||
|
Reg: prometheus.NewRegistry(),
|
||||||
|
zoneMap: make(map[string]struct{}),
|
||||||
|
}
|
||||||
|
// Add the default collectors
|
||||||
|
met.MustRegister(prometheus.NewGoCollector())
|
||||||
|
met.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
|
||||||
|
|
||||||
|
// Add all of our collectors
|
||||||
|
met.MustRegister(buildInfo)
|
||||||
|
met.MustRegister(vars.Panic)
|
||||||
|
met.MustRegister(vars.RequestCount)
|
||||||
|
met.MustRegister(vars.RequestDuration)
|
||||||
|
met.MustRegister(vars.RequestSize)
|
||||||
|
met.MustRegister(vars.RequestDo)
|
||||||
|
met.MustRegister(vars.RequestType)
|
||||||
|
met.MustRegister(vars.ResponseSize)
|
||||||
|
met.MustRegister(vars.ResponseRcode)
|
||||||
|
met.MustRegister(vars.PluginEnabled)
|
||||||
|
|
||||||
|
return met
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustRegister wraps m.Reg.MustRegister.
|
||||||
|
func (m *Metrics) MustRegister(c prometheus.Collector) {
|
||||||
|
err := m.Reg.Register(c)
|
||||||
|
if err != nil {
|
||||||
|
// ignore any duplicate error, but fatal on any other kind of error
|
||||||
|
if _, ok := err.(prometheus.AlreadyRegisteredError); !ok {
|
||||||
|
log.Fatalf("Cannot register metrics collector: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddZone adds zone z to m.
|
||||||
|
func (m *Metrics) AddZone(z string) {
|
||||||
|
m.zoneMu.Lock()
|
||||||
|
m.zoneMap[z] = struct{}{}
|
||||||
|
m.zoneNames = keys(m.zoneMap)
|
||||||
|
m.zoneMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveZone remove zone z from m.
|
||||||
|
func (m *Metrics) RemoveZone(z string) {
|
||||||
|
m.zoneMu.Lock()
|
||||||
|
delete(m.zoneMap, z)
|
||||||
|
m.zoneNames = keys(m.zoneMap)
|
||||||
|
m.zoneMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneNames returns the zones of m.
|
||||||
|
func (m *Metrics) ZoneNames() []string {
|
||||||
|
m.zoneMu.RLock()
|
||||||
|
s := m.zoneNames
|
||||||
|
m.zoneMu.RUnlock()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnStartup sets up the metrics on startup.
|
||||||
|
func (m *Metrics) OnStartup() error {
|
||||||
|
ln, err := reuseport.Listen("tcp", m.Addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to start metrics handler: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ln = ln
|
||||||
|
m.lnSetup = true
|
||||||
|
|
||||||
|
m.mux = http.NewServeMux()
|
||||||
|
m.mux.Handle("/metrics", promhttp.HandlerFor(m.Reg, promhttp.HandlerOpts{}))
|
||||||
|
|
||||||
|
// creating some helper variables to avoid data races on m.srv and m.ln
|
||||||
|
server := &http.Server{Handler: m.mux}
|
||||||
|
m.srv = server
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
server.Serve(ln)
|
||||||
|
}()
|
||||||
|
|
||||||
|
ListenAddr = ln.Addr().String() // For tests.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnRestart stops the listener on reload.
|
||||||
|
func (m *Metrics) OnRestart() error {
|
||||||
|
if !m.lnSetup {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
u.Unset(m.Addr)
|
||||||
|
return m.stopServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Metrics) stopServer() error {
|
||||||
|
if !m.lnSetup {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := m.srv.Shutdown(ctx); err != nil {
|
||||||
|
log.Infof("Failed to stop prometheus http server: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.lnSetup = false
|
||||||
|
m.ln.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnFinalShutdown tears down the metrics listener on shutdown and restart.
|
||||||
|
func (m *Metrics) OnFinalShutdown() error { return m.stopServer() }
|
||||||
|
|
||||||
|
func keys(m map[string]struct{}) []string {
|
||||||
|
sx := []string{}
|
||||||
|
for k := range m {
|
||||||
|
sx = append(sx, k)
|
||||||
|
}
|
||||||
|
return sx
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenAddr is assigned the address of the prometheus listener. Its use is mainly in tests where
|
||||||
|
// we listen on "localhost:0" and need to retrieve the actual address.
|
||||||
|
var ListenAddr string
|
||||||
|
|
||||||
|
// shutdownTimeout is the maximum amount of time the metrics plugin will wait
|
||||||
|
// before erroring when it tries to close the metrics server
|
||||||
|
const shutdownTimeout time.Duration = time.Second * 5
|
||||||
|
|
||||||
|
var buildInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Name: "build_info",
|
||||||
|
Help: "A metric with a constant '1' value labeled by version, revision, and goversion from which CoreDNS was built.",
|
||||||
|
}, []string{"version", "revision", "goversion"})
|
23
vendor/github.com/coredns/coredns/plugin/metrics/register.go
generated
vendored
Normal file
23
vendor/github.com/coredns/coredns/plugin/metrics/register.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MustRegister registers the prometheus Collectors when the metrics plugin is used.
|
||||||
|
func MustRegister(c *caddy.Controller, cs ...prometheus.Collector) {
|
||||||
|
m := dnsserver.GetConfig(c).Handler("prometheus")
|
||||||
|
if m == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x, ok := m.(*Metrics)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, c := range cs {
|
||||||
|
x.MustRegister(c)
|
||||||
|
}
|
||||||
|
}
|
28
vendor/github.com/coredns/coredns/plugin/metrics/registry.go
generated
vendored
Normal file
28
vendor/github.com/coredns/coredns/plugin/metrics/registry.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type reg struct {
|
||||||
|
sync.RWMutex
|
||||||
|
r map[string]*prometheus.Registry
|
||||||
|
}
|
||||||
|
|
||||||
|
func newReg() *reg { return ®{r: make(map[string]*prometheus.Registry)} }
|
||||||
|
|
||||||
|
// update sets the registry if not already there and returns the input. Or it returns
|
||||||
|
// a previous set value.
|
||||||
|
func (r *reg) getOrSet(addr string, pr *prometheus.Registry) *prometheus.Registry {
|
||||||
|
r.Lock()
|
||||||
|
defer r.Unlock()
|
||||||
|
|
||||||
|
if v, ok := r.r[addr]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
r.r[addr] = pr
|
||||||
|
return pr
|
||||||
|
}
|
105
vendor/github.com/coredns/coredns/plugin/metrics/setup.go
generated
vendored
Normal file
105
vendor/github.com/coredns/coredns/plugin/metrics/setup.go
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/core/dnsserver"
|
||||||
|
"github.com/coredns/coredns/coremain"
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/metrics/vars"
|
||||||
|
clog "github.com/coredns/coredns/plugin/pkg/log"
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/uniq"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
log = clog.NewWithPlugin("prometheus")
|
||||||
|
u = uniq.New()
|
||||||
|
registry = newReg()
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() { plugin.Register("prometheus", setup) }
|
||||||
|
|
||||||
|
func setup(c *caddy.Controller) error {
|
||||||
|
m, err := parse(c)
|
||||||
|
if err != nil {
|
||||||
|
return plugin.Error("prometheus", err)
|
||||||
|
}
|
||||||
|
m.Reg = registry.getOrSet(m.Addr, m.Reg)
|
||||||
|
|
||||||
|
c.OnStartup(func() error { m.Reg = registry.getOrSet(m.Addr, m.Reg); u.Set(m.Addr, m.OnStartup); return nil })
|
||||||
|
c.OnRestartFailed(func() error { m.Reg = registry.getOrSet(m.Addr, m.Reg); u.Set(m.Addr, m.OnStartup); return nil })
|
||||||
|
|
||||||
|
c.OnStartup(func() error { return u.ForEach() })
|
||||||
|
c.OnRestartFailed(func() error { return u.ForEach() })
|
||||||
|
|
||||||
|
c.OnStartup(func() error {
|
||||||
|
conf := dnsserver.GetConfig(c)
|
||||||
|
for _, h := range conf.ListenHosts {
|
||||||
|
addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port)
|
||||||
|
for _, p := range conf.Handlers() {
|
||||||
|
vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, p.Name()).Set(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.OnRestartFailed(func() error {
|
||||||
|
conf := dnsserver.GetConfig(c)
|
||||||
|
for _, h := range conf.ListenHosts {
|
||||||
|
addrstr := conf.Transport + "://" + net.JoinHostPort(h, conf.Port)
|
||||||
|
for _, p := range conf.Handlers() {
|
||||||
|
vars.PluginEnabled.WithLabelValues(addrstr, conf.Zone, p.Name()).Set(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
c.OnRestart(m.OnRestart)
|
||||||
|
c.OnRestart(func() error { vars.PluginEnabled.Reset(); return nil })
|
||||||
|
c.OnFinalShutdown(m.OnFinalShutdown)
|
||||||
|
|
||||||
|
// Initialize metrics.
|
||||||
|
buildInfo.WithLabelValues(coremain.CoreVersion, coremain.GitCommit, runtime.Version()).Set(1)
|
||||||
|
|
||||||
|
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
|
||||||
|
m.Next = next
|
||||||
|
return m
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(c *caddy.Controller) (*Metrics, error) {
|
||||||
|
met := New(defaultAddr)
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for c.Next() {
|
||||||
|
if i > 0 {
|
||||||
|
return nil, plugin.ErrOnce
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
|
||||||
|
for _, z := range c.ServerBlockKeys {
|
||||||
|
met.AddZone(plugin.Host(z).Normalize())
|
||||||
|
}
|
||||||
|
args := c.RemainingArgs()
|
||||||
|
|
||||||
|
switch len(args) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
met.Addr = args[0]
|
||||||
|
_, _, e := net.SplitHostPort(met.Addr)
|
||||||
|
if e != nil {
|
||||||
|
return met, e
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return met, c.ArgErr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return met, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultAddr is the address the where the metrics are exported by default.
|
||||||
|
const defaultAddr = "localhost:9153"
|
64
vendor/github.com/coredns/coredns/plugin/metrics/vars/report.go
generated
vendored
Normal file
64
vendor/github.com/coredns/coredns/plugin/metrics/vars/report.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package vars
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// not sent down the plugin chain.
|
||||||
|
func Report(server string, req request.Request, zone, rcode string, size int, start time.Time) {
|
||||||
|
// Proto and Family.
|
||||||
|
net := req.Proto()
|
||||||
|
fam := "1"
|
||||||
|
if req.Family() == 2 {
|
||||||
|
fam = "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := req.QType()
|
||||||
|
RequestCount.WithLabelValues(server, zone, net, fam).Inc()
|
||||||
|
|
||||||
|
if req.Do() {
|
||||||
|
RequestDo.WithLabelValues(server, zone).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, known := monitorType[typ]; known {
|
||||||
|
RequestType.WithLabelValues(server, zone, dns.Type(typ).String()).Inc()
|
||||||
|
RequestDuration.WithLabelValues(server, zone, dns.Type(typ).String()).Observe(time.Since(start).Seconds())
|
||||||
|
} else {
|
||||||
|
RequestType.WithLabelValues(server, zone, other).Inc()
|
||||||
|
RequestDuration.WithLabelValues(server, zone, other).Observe(time.Since(start).Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
ResponseSize.WithLabelValues(server, zone, net).Observe(float64(size))
|
||||||
|
RequestSize.WithLabelValues(server, zone, net).Observe(float64(req.Len()))
|
||||||
|
|
||||||
|
ResponseRcode.WithLabelValues(server, zone, rcode).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
var monitorType = map[uint16]struct{}{
|
||||||
|
dns.TypeAAAA: {},
|
||||||
|
dns.TypeA: {},
|
||||||
|
dns.TypeCNAME: {},
|
||||||
|
dns.TypeDNSKEY: {},
|
||||||
|
dns.TypeDS: {},
|
||||||
|
dns.TypeMX: {},
|
||||||
|
dns.TypeNSEC3: {},
|
||||||
|
dns.TypeNSEC: {},
|
||||||
|
dns.TypeNS: {},
|
||||||
|
dns.TypePTR: {},
|
||||||
|
dns.TypeRRSIG: {},
|
||||||
|
dns.TypeSOA: {},
|
||||||
|
dns.TypeSRV: {},
|
||||||
|
dns.TypeTXT: {},
|
||||||
|
// Meta Qtypes
|
||||||
|
dns.TypeIXFR: {},
|
||||||
|
dns.TypeAXFR: {},
|
||||||
|
dns.TypeANY: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
const other = "other"
|
81
vendor/github.com/coredns/coredns/plugin/metrics/vars/vars.go
generated
vendored
Normal file
81
vendor/github.com/coredns/coredns/plugin/metrics/vars/vars.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package vars
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Request* and Response* are the prometheus counters and gauges we are using for exporting metrics.
|
||||||
|
var (
|
||||||
|
RequestCount = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "request_count_total",
|
||||||
|
Help: "Counter of DNS requests made per zone, protocol and family.",
|
||||||
|
}, []string{"server", "zone", "proto", "family"})
|
||||||
|
|
||||||
|
RequestDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "request_duration_seconds",
|
||||||
|
Buckets: plugin.TimeBuckets,
|
||||||
|
Help: "Histogram of the time (in seconds) each request took.",
|
||||||
|
}, []string{"server", "zone", "type"})
|
||||||
|
|
||||||
|
RequestSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "request_size_bytes",
|
||||||
|
Help: "Size of the EDNS0 UDP buffer in bytes (64K for TCP).",
|
||||||
|
Buckets: []float64{0, 100, 200, 300, 400, 511, 1023, 2047, 4095, 8291, 16e3, 32e3, 48e3, 64e3},
|
||||||
|
}, []string{"server", "zone", "proto"})
|
||||||
|
|
||||||
|
RequestDo = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "request_do_count_total",
|
||||||
|
Help: "Counter of DNS requests with DO bit set per zone.",
|
||||||
|
}, []string{"server", "zone"})
|
||||||
|
|
||||||
|
RequestType = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "request_type_count_total",
|
||||||
|
Help: "Counter of DNS requests per type, per zone.",
|
||||||
|
}, []string{"server", "zone", "type"})
|
||||||
|
|
||||||
|
ResponseSize = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "response_size_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},
|
||||||
|
}, []string{"server", "zone", "proto"})
|
||||||
|
|
||||||
|
ResponseRcode = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Subsystem: subsystem,
|
||||||
|
Name: "response_rcode_count_total",
|
||||||
|
Help: "Counter of response status codes.",
|
||||||
|
}, []string{"server", "zone", "rcode"})
|
||||||
|
|
||||||
|
Panic = prometheus.NewCounter(prometheus.CounterOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Name: "panic_count_total",
|
||||||
|
Help: "A metrics that counts the number of panics.",
|
||||||
|
})
|
||||||
|
|
||||||
|
PluginEnabled = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
Namespace: plugin.Namespace,
|
||||||
|
Name: "plugin_enabled",
|
||||||
|
Help: "A metric that indicates whether a plugin is enabled on per server and zone basis.",
|
||||||
|
}, []string{"server", "zone", "name"})
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
subsystem = "dns"
|
||||||
|
|
||||||
|
// Dropped indicates we dropped the query before any handling. It has no closing dot, so it can not be a valid zone.
|
||||||
|
Dropped = "dropped"
|
||||||
|
)
|
142
vendor/github.com/coredns/coredns/plugin/normalize.go
generated
vendored
Normal file
142
vendor/github.com/coredns/coredns/plugin/normalize.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/parse"
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// See core/dnsserver/address.go - we should unify these two impls.
|
||||||
|
|
||||||
|
// Zones represents a lists of zone names.
|
||||||
|
type Zones []string
|
||||||
|
|
||||||
|
// Matches checks if qname is a subdomain of any of the zones in z. The match
|
||||||
|
// will return the most specific zones that matches. The empty string
|
||||||
|
// signals a not found condition.
|
||||||
|
func (z Zones) Matches(qname string) string {
|
||||||
|
zone := ""
|
||||||
|
for _, zname := range z {
|
||||||
|
if dns.IsSubDomain(zname, qname) {
|
||||||
|
// We want the *longest* matching zone, otherwise we may end up in a parent
|
||||||
|
if len(zname) > len(zone) {
|
||||||
|
zone = zname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return zone
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize fully qualifies all zones in z. The zones in Z must be domain names, without
|
||||||
|
// a port or protocol prefix.
|
||||||
|
func (z Zones) Normalize() {
|
||||||
|
for i := range z {
|
||||||
|
z[i] = Name(z[i]).Normalize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name represents a domain name.
|
||||||
|
type Name string
|
||||||
|
|
||||||
|
// Matches checks to see if other is a subdomain (or the same domain) of n.
|
||||||
|
// This method assures that names can be easily and consistently matched.
|
||||||
|
func (n Name) Matches(child string) bool {
|
||||||
|
if dns.Name(n) == dns.Name(child) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return dns.IsSubDomain(string(n), child)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize lowercases and makes n fully qualified.
|
||||||
|
func (n Name) Normalize() string { return strings.ToLower(dns.Fqdn(string(n))) }
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Host represents a host from the Corefile, may contain port.
|
||||||
|
Host string
|
||||||
|
)
|
||||||
|
|
||||||
|
// Normalize will return the host portion of host, stripping
|
||||||
|
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||||
|
// An empty string is returned on failure
|
||||||
|
func (h Host) Normalize() string {
|
||||||
|
// The error can be ignored here, because this function should only be called after the corefile has already been vetted.
|
||||||
|
host, _ := h.MustNormalize()
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustNormalize will return the host portion of host, stripping
|
||||||
|
// of any port or transport. The host will also be fully qualified and lowercased.
|
||||||
|
// An error is returned on error
|
||||||
|
func (h Host) MustNormalize() (string, error) {
|
||||||
|
s := string(h)
|
||||||
|
_, s = parse.Transport(s)
|
||||||
|
|
||||||
|
// The error can be ignored here, because this function is called after the corefile has already been vetted.
|
||||||
|
host, _, _, err := SplitHostPort(s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return Name(host).Normalize(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitHostPort splits s up in a host and port portion, taking reverse address notation into account.
|
||||||
|
// String the string s should *not* be prefixed with any protocols, i.e. dns://. The returned ipnet is the
|
||||||
|
// *net.IPNet that is used when the zone is a reverse and a netmask is given.
|
||||||
|
func SplitHostPort(s string) (host, port string, ipnet *net.IPNet, err error) {
|
||||||
|
// If there is: :[0-9]+ on the end we assume this is the port. This works for (ascii) domain
|
||||||
|
// names and our reverse syntax, which always needs a /mask *before* the port.
|
||||||
|
// So from the back, find first colon, and then check if it's a number.
|
||||||
|
host = s
|
||||||
|
|
||||||
|
colon := strings.LastIndex(s, ":")
|
||||||
|
if colon == len(s)-1 {
|
||||||
|
return "", "", nil, fmt.Errorf("expecting data after last colon: %q", s)
|
||||||
|
}
|
||||||
|
if colon != -1 {
|
||||||
|
if p, err := strconv.Atoi(s[colon+1:]); err == nil {
|
||||||
|
port = strconv.Itoa(p)
|
||||||
|
host = s[:colon]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(miek): this should take escaping into account.
|
||||||
|
if len(host) > 255 {
|
||||||
|
return "", "", nil, fmt.Errorf("specified zone is too long: %d > 255", len(host))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, d := dns.IsDomainName(host)
|
||||||
|
if !d {
|
||||||
|
return "", "", nil, fmt.Errorf("zone is not a valid domain name: %s", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it parses as a reverse zone, if so we use that. Must be fully specified IP and mask.
|
||||||
|
ip, n, err := net.ParseCIDR(host)
|
||||||
|
ones, bits := 0, 0
|
||||||
|
if err == nil {
|
||||||
|
if rev, e := dns.ReverseAddr(ip.String()); e == nil {
|
||||||
|
ones, bits = n.Mask.Size()
|
||||||
|
// get the size, in bits, of each portion of hostname defined in the reverse address. (8 for IPv4, 4 for IPv6)
|
||||||
|
sizeDigit := 8
|
||||||
|
if len(n.IP) == net.IPv6len {
|
||||||
|
sizeDigit = 4
|
||||||
|
}
|
||||||
|
// Get the first lower octet boundary to see what encompassing zone we should be authoritative for.
|
||||||
|
mod := (bits - ones) % sizeDigit
|
||||||
|
nearest := (bits - ones) + mod
|
||||||
|
offset := 0
|
||||||
|
var end bool
|
||||||
|
for i := 0; i < nearest/sizeDigit; i++ {
|
||||||
|
offset, end = dns.NextLabel(rev, offset)
|
||||||
|
if end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host = rev[offset:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return host, port, n, nil
|
||||||
|
}
|
41
vendor/github.com/coredns/coredns/plugin/pkg/dnstest/multirecorder.go
generated
vendored
Normal file
41
vendor/github.com/coredns/coredns/plugin/pkg/dnstest/multirecorder.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package dnstest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MultiRecorder is a type of ResponseWriter that captures all messages written to it.
|
||||||
|
type MultiRecorder struct {
|
||||||
|
Len int
|
||||||
|
Msgs []*dns.Msg
|
||||||
|
Start time.Time
|
||||||
|
dns.ResponseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMultiRecorder makes and returns a new MultiRecorder.
|
||||||
|
func NewMultiRecorder(w dns.ResponseWriter) *MultiRecorder {
|
||||||
|
return &MultiRecorder{
|
||||||
|
ResponseWriter: w,
|
||||||
|
Msgs: make([]*dns.Msg, 0),
|
||||||
|
Start: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteMsg records the message and its length written to it and call the
|
||||||
|
// underlying ResponseWriter's WriteMsg method.
|
||||||
|
func (r *MultiRecorder) WriteMsg(res *dns.Msg) error {
|
||||||
|
r.Len += res.Len()
|
||||||
|
r.Msgs = append(r.Msgs, res)
|
||||||
|
return r.ResponseWriter.WriteMsg(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is a wrapper that records the length of the messages that get written to it.
|
||||||
|
func (r *MultiRecorder) Write(buf []byte) (int, error) {
|
||||||
|
n, err := r.ResponseWriter.Write(buf)
|
||||||
|
if err == nil {
|
||||||
|
r.Len += n
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
54
vendor/github.com/coredns/coredns/plugin/pkg/dnstest/recorder.go
generated
vendored
Normal file
54
vendor/github.com/coredns/coredns/plugin/pkg/dnstest/recorder.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Package dnstest allows for easy testing of DNS client against a test server.
|
||||||
|
package dnstest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Recorder is a type of ResponseWriter that captures
|
||||||
|
// the rcode code written to it and also the size of the message
|
||||||
|
// written in the response. A rcode code does not have
|
||||||
|
// to be written, however, in which case 0 must be assumed.
|
||||||
|
// It is best to have the constructor initialize this type
|
||||||
|
// with that default status code.
|
||||||
|
type Recorder struct {
|
||||||
|
dns.ResponseWriter
|
||||||
|
Rcode int
|
||||||
|
Len int
|
||||||
|
Msg *dns.Msg
|
||||||
|
Start time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRecorder makes and returns a new Recorder,
|
||||||
|
// which captures the DNS rcode from the ResponseWriter
|
||||||
|
// and also the length of the response message written through it.
|
||||||
|
func NewRecorder(w dns.ResponseWriter) *Recorder {
|
||||||
|
return &Recorder{
|
||||||
|
ResponseWriter: w,
|
||||||
|
Rcode: 0,
|
||||||
|
Msg: nil,
|
||||||
|
Start: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteMsg records the status code and calls the
|
||||||
|
// underlying ResponseWriter's WriteMsg method.
|
||||||
|
func (r *Recorder) WriteMsg(res *dns.Msg) error {
|
||||||
|
r.Rcode = res.Rcode
|
||||||
|
// We may get called multiple times (axfr for instance).
|
||||||
|
// Save the last message, but add the sizes.
|
||||||
|
r.Len += res.Len()
|
||||||
|
r.Msg = res
|
||||||
|
return r.ResponseWriter.WriteMsg(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is a wrapper that records the length of the message that gets written.
|
||||||
|
func (r *Recorder) Write(buf []byte) (int, error) {
|
||||||
|
n, err := r.ResponseWriter.Write(buf)
|
||||||
|
if err == nil {
|
||||||
|
r.Len += n
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
65
vendor/github.com/coredns/coredns/plugin/pkg/dnstest/server.go
generated
vendored
Normal file
65
vendor/github.com/coredns/coredns/plugin/pkg/dnstest/server.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package dnstest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Server is an DNS server listening on a system-chosen port on the local
|
||||||
|
// loopback interface, for use in end-to-end DNS tests.
|
||||||
|
type Server struct {
|
||||||
|
Addr string // Address where the server listening.
|
||||||
|
|
||||||
|
s1 *dns.Server // udp
|
||||||
|
s2 *dns.Server // tcp
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServer starts and returns a new Server. The caller should call Close when
|
||||||
|
// finished, to shut it down.
|
||||||
|
func NewServer(f dns.HandlerFunc) *Server {
|
||||||
|
dns.HandleFunc(".", f)
|
||||||
|
|
||||||
|
ch1 := make(chan bool)
|
||||||
|
ch2 := make(chan bool)
|
||||||
|
|
||||||
|
s1 := &dns.Server{} // udp
|
||||||
|
s2 := &dns.Server{} // tcp
|
||||||
|
|
||||||
|
for i := 0; i < 5; i++ { // 5 attempts
|
||||||
|
s2.Listener, _ = reuseport.Listen("tcp", ":0")
|
||||||
|
if s2.Listener == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s1.PacketConn, _ = net.ListenPacket("udp", s2.Listener.Addr().String())
|
||||||
|
if s1.PacketConn != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// perhaps UPD port is in use, try again
|
||||||
|
s2.Listener.Close()
|
||||||
|
s2.Listener = nil
|
||||||
|
}
|
||||||
|
if s2.Listener == nil {
|
||||||
|
panic("dnstest.NewServer(): failed to create new server")
|
||||||
|
}
|
||||||
|
|
||||||
|
s1.NotifyStartedFunc = func() { close(ch1) }
|
||||||
|
s2.NotifyStartedFunc = func() { close(ch2) }
|
||||||
|
go s1.ActivateAndServe()
|
||||||
|
go s2.ActivateAndServe()
|
||||||
|
|
||||||
|
<-ch1
|
||||||
|
<-ch2
|
||||||
|
|
||||||
|
return &Server{s1: s1, s2: s2, Addr: s2.Listener.Addr().String()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close shuts down the server.
|
||||||
|
func (s *Server) Close() {
|
||||||
|
s.s1.Shutdown()
|
||||||
|
s.s2.Shutdown()
|
||||||
|
}
|
15
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/cname.go
generated
vendored
Normal file
15
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/cname.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import "github.com/miekg/dns"
|
||||||
|
|
||||||
|
// DuplicateCNAME returns true if r already exists in records.
|
||||||
|
func DuplicateCNAME(r *dns.CNAME, records []dns.RR) bool {
|
||||||
|
for _, rec := range records {
|
||||||
|
if v, ok := rec.(*dns.CNAME); ok {
|
||||||
|
if v.Target == r.Target {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
2
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/doc.go
generated
vendored
Normal file
2
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// Package dnsutil contains DNS related helper functions.
|
||||||
|
package dnsutil
|
17
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/join.go
generated
vendored
Normal file
17
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/join.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Join joins labels to form a fully qualified domain name. If the last label is
|
||||||
|
// the root label it is ignored. Not other syntax checks are performed.
|
||||||
|
func Join(labels ...string) string {
|
||||||
|
ll := len(labels)
|
||||||
|
if labels[ll-1] == "." {
|
||||||
|
return strings.Join(labels[:ll-1], ".") + "."
|
||||||
|
}
|
||||||
|
return dns.Fqdn(strings.Join(labels, "."))
|
||||||
|
}
|
81
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/reverse.go
generated
vendored
Normal file
81
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/reverse.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtractAddressFromReverse turns a standard PTR reverse record name
|
||||||
|
// into an IP address. This works for ipv4 or ipv6.
|
||||||
|
//
|
||||||
|
// 54.119.58.176.in-addr.arpa. becomes 176.58.119.54. If the conversion
|
||||||
|
// fails the empty string is returned.
|
||||||
|
func ExtractAddressFromReverse(reverseName string) string {
|
||||||
|
search := ""
|
||||||
|
|
||||||
|
f := reverse
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasSuffix(reverseName, IP4arpa):
|
||||||
|
search = strings.TrimSuffix(reverseName, IP4arpa)
|
||||||
|
case strings.HasSuffix(reverseName, IP6arpa):
|
||||||
|
search = strings.TrimSuffix(reverseName, IP6arpa)
|
||||||
|
f = reverse6
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the segments and then combine them.
|
||||||
|
return f(strings.Split(search, "."))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsReverse returns 0 is name is not in a reverse zone. Anything > 0 indicates
|
||||||
|
// name is in a reverse zone. The returned integer will be 1 for in-addr.arpa. (IPv4)
|
||||||
|
// and 2 for ip6.arpa. (IPv6).
|
||||||
|
func IsReverse(name string) int {
|
||||||
|
if strings.HasSuffix(name, IP4arpa) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(name, IP6arpa) {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func reverse(slice []string) string {
|
||||||
|
for i := 0; i < len(slice)/2; i++ {
|
||||||
|
j := len(slice) - i - 1
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
}
|
||||||
|
ip := net.ParseIP(strings.Join(slice, ".")).To4()
|
||||||
|
if ip == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverse6 reverse the segments and combine them according to RFC3596:
|
||||||
|
// b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2
|
||||||
|
// is reversed to 2001:db8::567:89ab
|
||||||
|
func reverse6(slice []string) string {
|
||||||
|
for i := 0; i < len(slice)/2; i++ {
|
||||||
|
j := len(slice) - i - 1
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
}
|
||||||
|
slice6 := []string{}
|
||||||
|
for i := 0; i < len(slice)/4; i++ {
|
||||||
|
slice6 = append(slice6, strings.Join(slice[i*4:i*4+4], ""))
|
||||||
|
}
|
||||||
|
ip := net.ParseIP(strings.Join(slice6, ":")).To16()
|
||||||
|
if ip == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// IP4arpa is the reverse tree suffix for v4 IP addresses.
|
||||||
|
IP4arpa = ".in-addr.arpa."
|
||||||
|
// IP6arpa is the reverse tree suffix for v6 IP addresses.
|
||||||
|
IP6arpa = ".ip6.arpa."
|
||||||
|
)
|
52
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/ttl.go
generated
vendored
Normal file
52
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/ttl.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/response"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MinimalTTL scans the message returns the lowest TTL found taking into the response.Type of the message.
|
||||||
|
func MinimalTTL(m *dns.Msg, mt response.Type) time.Duration {
|
||||||
|
if mt != response.NoError && mt != response.NameError && mt != response.NoData {
|
||||||
|
return MinimalDefaultTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
// No records or OPT is the only record, return a short ttl as a fail safe.
|
||||||
|
if len(m.Answer)+len(m.Ns) == 0 &&
|
||||||
|
(len(m.Extra) == 0 || (len(m.Extra) == 1 && m.Extra[0].Header().Rrtype == dns.TypeOPT)) {
|
||||||
|
return MinimalDefaultTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
minTTL := MaximumDefaulTTL
|
||||||
|
for _, r := range m.Answer {
|
||||||
|
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||||
|
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, r := range m.Ns {
|
||||||
|
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||||
|
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range m.Extra {
|
||||||
|
if r.Header().Rrtype == dns.TypeOPT {
|
||||||
|
// OPT records use TTL field for extended rcode and flags
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r.Header().Ttl < uint32(minTTL.Seconds()) {
|
||||||
|
minTTL = time.Duration(r.Header().Ttl) * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minTTL
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MinimalDefaultTTL is the absolute lowest TTL we use in CoreDNS.
|
||||||
|
MinimalDefaultTTL = 5 * time.Second
|
||||||
|
// MaximumDefaulTTL is the maximum TTL was use on RRsets in CoreDNS.
|
||||||
|
MaximumDefaulTTL = 1 * time.Hour
|
||||||
|
)
|
20
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/zone.go
generated
vendored
Normal file
20
vendor/github.com/coredns/coredns/plugin/pkg/dnsutil/zone.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package dnsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TrimZone removes the zone component from q. It returns the trimmed
|
||||||
|
// name or an error is zone is longer then qname. The trimmed name will be returned
|
||||||
|
// without a trailing dot.
|
||||||
|
func TrimZone(q string, z string) (string, error) {
|
||||||
|
zl := dns.CountLabel(z)
|
||||||
|
i, ok := dns.PrevLabel(q, zl)
|
||||||
|
if ok || i-1 < 0 {
|
||||||
|
return "", errors.New("trimzone: overshot qname: " + q + "for zone " + z)
|
||||||
|
}
|
||||||
|
// This includes the '.', remove on return
|
||||||
|
return q[:i-1], nil
|
||||||
|
}
|
119
vendor/github.com/coredns/coredns/plugin/pkg/doh/doh.go
generated
vendored
Normal file
119
vendor/github.com/coredns/coredns/plugin/pkg/doh/doh.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package doh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MimeType is the DoH mimetype that should be used.
|
||||||
|
const MimeType = "application/dns-message"
|
||||||
|
|
||||||
|
// Path is the URL path that should be used.
|
||||||
|
const Path = "/dns-query"
|
||||||
|
|
||||||
|
// NewRequest returns a new DoH request given a method, URL (without any paths, so exclude /dns-query) and dns.Msg.
|
||||||
|
func NewRequest(method, url string, m *dns.Msg) (*http.Request, error) {
|
||||||
|
buf, err := m.Pack()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch method {
|
||||||
|
case http.MethodGet:
|
||||||
|
b64 := base64.RawURLEncoding.EncodeToString(buf)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "https://"+url+Path+"?dns="+b64, nil)
|
||||||
|
if err != nil {
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("content-type", MimeType)
|
||||||
|
req.Header.Set("accept", MimeType)
|
||||||
|
return req, nil
|
||||||
|
|
||||||
|
case http.MethodPost:
|
||||||
|
req, err := http.NewRequest(http.MethodPost, "https://"+url+Path+"?bla=foo:443", bytes.NewReader(buf))
|
||||||
|
if err != nil {
|
||||||
|
return req, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("content-type", MimeType)
|
||||||
|
req.Header.Set("accept", MimeType)
|
||||||
|
return req, nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("method not allowed: %s", method)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseToMsg converts a http.Response to a dns message.
|
||||||
|
func ResponseToMsg(resp *http.Response) (*dns.Msg, error) {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return toMsg(resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestToMsg converts a http.Request to a dns message.
|
||||||
|
func RequestToMsg(req *http.Request) (*dns.Msg, error) {
|
||||||
|
switch req.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
return requestToMsgGet(req)
|
||||||
|
|
||||||
|
case http.MethodPost:
|
||||||
|
return requestToMsgPost(req)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("method not allowed: %s", req.Method)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// requestToMsgPost extracts the dns message from the request body.
|
||||||
|
func requestToMsgPost(req *http.Request) (*dns.Msg, error) {
|
||||||
|
defer req.Body.Close()
|
||||||
|
return toMsg(req.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// requestToMsgGet extract the dns message from the GET request.
|
||||||
|
func requestToMsgGet(req *http.Request) (*dns.Msg, error) {
|
||||||
|
values := req.URL.Query()
|
||||||
|
b64, ok := values["dns"]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("no 'dns' query parameter found")
|
||||||
|
}
|
||||||
|
if len(b64) != 1 {
|
||||||
|
return nil, fmt.Errorf("multiple 'dns' query values found")
|
||||||
|
}
|
||||||
|
return base64ToMsg(b64[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func toMsg(r io.ReadCloser) (*dns.Msg, error) {
|
||||||
|
buf, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m := new(dns.Msg)
|
||||||
|
err = m.Unpack(buf)
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func base64ToMsg(b64 string) (*dns.Msg, error) {
|
||||||
|
buf, err := b64Enc.DecodeString(b64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := new(dns.Msg)
|
||||||
|
err = m.Unpack(buf)
|
||||||
|
|
||||||
|
return m, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var b64Enc = base64.RawURLEncoding
|
74
vendor/github.com/coredns/coredns/plugin/pkg/edns/edns.go
generated
vendored
Normal file
74
vendor/github.com/coredns/coredns/plugin/pkg/edns/edns.go
generated
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Package edns provides function useful for adding/inspecting OPT records to/in messages.
|
||||||
|
package edns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sup = &supported{m: make(map[uint16]struct{})}
|
||||||
|
|
||||||
|
type supported struct {
|
||||||
|
m map[uint16]struct{}
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSupportedOption adds a new supported option the set of EDNS0 options that we support. Plugins typically call
|
||||||
|
// this in their setup code to signal support for a new option.
|
||||||
|
// By default we support:
|
||||||
|
// dns.EDNS0NSID, dns.EDNS0EXPIRE, dns.EDNS0COOKIE, dns.EDNS0TCPKEEPALIVE, dns.EDNS0PADDING. These
|
||||||
|
// values are not in this map and checked directly in the server.
|
||||||
|
func SetSupportedOption(option uint16) {
|
||||||
|
sup.Lock()
|
||||||
|
sup.m[option] = struct{}{}
|
||||||
|
sup.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SupportedOption returns true if the option code is supported as an extra EDNS0 option.
|
||||||
|
func SupportedOption(option uint16) bool {
|
||||||
|
sup.RLock()
|
||||||
|
_, ok := sup.m[option]
|
||||||
|
sup.RUnlock()
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version checks the EDNS version in the request. If error
|
||||||
|
// is nil everything is OK and we can invoke the plugin. If non-nil, the
|
||||||
|
// returned Msg is valid to be returned to the client (and should). For some
|
||||||
|
// reason this response should not contain a question RR in the question section.
|
||||||
|
func Version(req *dns.Msg) (*dns.Msg, error) {
|
||||||
|
opt := req.IsEdns0()
|
||||||
|
if opt == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if opt.Version() == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetReply(req)
|
||||||
|
// zero out question section, wtf.
|
||||||
|
m.Question = nil
|
||||||
|
|
||||||
|
o := new(dns.OPT)
|
||||||
|
o.Hdr.Name = "."
|
||||||
|
o.Hdr.Rrtype = dns.TypeOPT
|
||||||
|
o.SetVersion(0)
|
||||||
|
m.Rcode = dns.RcodeBadVers
|
||||||
|
o.SetExtendedRcode(dns.RcodeBadVers)
|
||||||
|
m.Extra = []dns.RR{o}
|
||||||
|
|
||||||
|
return m, errors.New("EDNS0 BADVERS")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns a normalized size based on proto.
|
||||||
|
func Size(proto string, size uint16) uint16 {
|
||||||
|
if proto == "tcp" {
|
||||||
|
return dns.MaxMsgSize
|
||||||
|
}
|
||||||
|
if size < dns.MinMsgSize {
|
||||||
|
return dns.MinMsgSize
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
113
vendor/github.com/coredns/coredns/plugin/pkg/log/log.go
generated
vendored
Normal file
113
vendor/github.com/coredns/coredns/plugin/pkg/log/log.go
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Package log implements a small wrapper around the std lib log package. It
|
||||||
|
// implements log levels by prefixing the logs with [INFO], [DEBUG], [WARNING]
|
||||||
|
// or [ERROR]. Debug logging is available and enabled if the *debug* plugin is
|
||||||
|
// used.
|
||||||
|
//
|
||||||
|
// log.Info("this is some logging"), will log on the Info level.
|
||||||
|
//
|
||||||
|
// log.Debug("this is debug output"), will log in the Debug level, etc.
|
||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
golog "log"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// D controls whether we should output debug logs. If true, we do, once set
|
||||||
|
// it can not be unset.
|
||||||
|
var D = &d{}
|
||||||
|
|
||||||
|
type d struct {
|
||||||
|
on bool
|
||||||
|
sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set enables debug logging.
|
||||||
|
func (d *d) Set() {
|
||||||
|
d.Lock()
|
||||||
|
d.on = true
|
||||||
|
d.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear disables debug logging.
|
||||||
|
func (d *d) Clear() {
|
||||||
|
d.Lock()
|
||||||
|
d.on = false
|
||||||
|
d.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value returns if debug logging is enabled.
|
||||||
|
func (d *d) Value() bool {
|
||||||
|
d.RLock()
|
||||||
|
b := d.on
|
||||||
|
d.RUnlock()
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// logf calls log.Printf prefixed with level.
|
||||||
|
func logf(level, format string, v ...interface{}) {
|
||||||
|
golog.Print(level, fmt.Sprintf(format, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// log calls log.Print prefixed with level.
|
||||||
|
func log(level string, v ...interface{}) {
|
||||||
|
golog.Print(level, fmt.Sprint(v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug is equivalent to log.Print(), but prefixed with "[DEBUG] ". It only outputs something
|
||||||
|
// if D is true.
|
||||||
|
func Debug(v ...interface{}) {
|
||||||
|
if !D.Value() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log(debug, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf is equivalent to log.Printf(), but prefixed with "[DEBUG] ". It only outputs something
|
||||||
|
// if D is true.
|
||||||
|
func Debugf(format string, v ...interface{}) {
|
||||||
|
if !D.Value() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logf(debug, format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info is equivalent to log.Print, but prefixed with "[INFO] ".
|
||||||
|
func Info(v ...interface{}) { log(info, v...) }
|
||||||
|
|
||||||
|
// Infof is equivalent to log.Printf, but prefixed with "[INFO] ".
|
||||||
|
func Infof(format string, v ...interface{}) { logf(info, format, v...) }
|
||||||
|
|
||||||
|
// Warning is equivalent to log.Print, but prefixed with "[WARNING] ".
|
||||||
|
func Warning(v ...interface{}) { log(warning, v...) }
|
||||||
|
|
||||||
|
// Warningf is equivalent to log.Printf, but prefixed with "[WARNING] ".
|
||||||
|
func Warningf(format string, v ...interface{}) { logf(warning, format, v...) }
|
||||||
|
|
||||||
|
// Error is equivalent to log.Print, but prefixed with "[ERROR] ".
|
||||||
|
func Error(v ...interface{}) { log(err, v...) }
|
||||||
|
|
||||||
|
// Errorf is equivalent to log.Printf, but prefixed with "[ERROR] ".
|
||||||
|
func Errorf(format string, v ...interface{}) { logf(err, format, v...) }
|
||||||
|
|
||||||
|
// Fatal is equivalent to log.Print, but prefixed with "[FATAL] ", and calling
|
||||||
|
// os.Exit(1).
|
||||||
|
func Fatal(v ...interface{}) { log(fatal, v...); os.Exit(1) }
|
||||||
|
|
||||||
|
// Fatalf is equivalent to log.Printf, but prefixed with "[FATAL] ", and calling
|
||||||
|
// os.Exit(1)
|
||||||
|
func Fatalf(format string, v ...interface{}) { logf(fatal, format, v...); os.Exit(1) }
|
||||||
|
|
||||||
|
// Discard sets the log output to /dev/null.
|
||||||
|
func Discard() { golog.SetOutput(ioutil.Discard) }
|
||||||
|
|
||||||
|
const (
|
||||||
|
debug = "[DEBUG] "
|
||||||
|
err = "[ERROR] "
|
||||||
|
fatal = "[FATAL] "
|
||||||
|
info = "[INFO] "
|
||||||
|
warning = "[WARNING] "
|
||||||
|
)
|
63
vendor/github.com/coredns/coredns/plugin/pkg/log/plugin.go
generated
vendored
Normal file
63
vendor/github.com/coredns/coredns/plugin/pkg/log/plugin.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package log
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// P is a logger that includes the plugin doing the logging.
|
||||||
|
type P struct {
|
||||||
|
plugin string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithPlugin returns a logger that includes "plugin/name: " in the log message.
|
||||||
|
// I.e [INFO] plugin/<name>: message.
|
||||||
|
func NewWithPlugin(name string) P { return P{"plugin/" + name + ": "} }
|
||||||
|
|
||||||
|
func (p P) logf(level, format string, v ...interface{}) {
|
||||||
|
log(level, p.plugin, fmt.Sprintf(format, v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p P) log(level string, v ...interface{}) {
|
||||||
|
log(level+p.plugin, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs as log.Debug.
|
||||||
|
func (p P) Debug(v ...interface{}) {
|
||||||
|
if !D.Value() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.log(debug, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs as log.Debugf.
|
||||||
|
func (p P) Debugf(format string, v ...interface{}) {
|
||||||
|
if !D.Value() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.logf(debug, format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs as log.Info.
|
||||||
|
func (p P) Info(v ...interface{}) { p.log(info, v...) }
|
||||||
|
|
||||||
|
// Infof logs as log.Infof.
|
||||||
|
func (p P) Infof(format string, v ...interface{}) { p.logf(info, format, v...) }
|
||||||
|
|
||||||
|
// Warning logs as log.Warning.
|
||||||
|
func (p P) Warning(v ...interface{}) { p.log(warning, v...) }
|
||||||
|
|
||||||
|
// Warningf logs as log.Warningf.
|
||||||
|
func (p P) Warningf(format string, v ...interface{}) { p.logf(warning, format, v...) }
|
||||||
|
|
||||||
|
// Error logs as log.Error.
|
||||||
|
func (p P) Error(v ...interface{}) { p.log(err, v...) }
|
||||||
|
|
||||||
|
// Errorf logs as log.Errorf.
|
||||||
|
func (p P) Errorf(format string, v ...interface{}) { p.logf(err, format, v...) }
|
||||||
|
|
||||||
|
// Fatal logs as log.Fatal and calls os.Exit(1).
|
||||||
|
func (p P) Fatal(v ...interface{}) { p.log(fatal, v...); 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) }
|
21
vendor/github.com/coredns/coredns/plugin/pkg/nonwriter/nonwriter.go
generated
vendored
Normal file
21
vendor/github.com/coredns/coredns/plugin/pkg/nonwriter/nonwriter.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Package nonwriter implements a dns.ResponseWriter that never writes, but captures the dns.Msg being written.
|
||||||
|
package nonwriter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Writer is a type of ResponseWriter that captures the message, but never writes to the client.
|
||||||
|
type Writer struct {
|
||||||
|
dns.ResponseWriter
|
||||||
|
Msg *dns.Msg
|
||||||
|
}
|
||||||
|
|
||||||
|
// New makes and returns a new NonWriter.
|
||||||
|
func New(w dns.ResponseWriter) *Writer { return &Writer{ResponseWriter: w} }
|
||||||
|
|
||||||
|
// WriteMsg records the message, but doesn't write it itself.
|
||||||
|
func (w *Writer) WriteMsg(res *dns.Msg) error {
|
||||||
|
w.Msg = res
|
||||||
|
return nil
|
||||||
|
}
|
112
vendor/github.com/coredns/coredns/plugin/pkg/parse/host.go
generated
vendored
Normal file
112
vendor/github.com/coredns/coredns/plugin/pkg/parse/host.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Strips the zone, but preserves any port that comes after the zone
|
||||||
|
func stripZone(host string) string {
|
||||||
|
if strings.Contains(host, "%") {
|
||||||
|
lastPercent := strings.LastIndex(host, "%")
|
||||||
|
newHost := host[:lastPercent]
|
||||||
|
return newHost
|
||||||
|
}
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostPortOrFile parses the strings in s, each string can either be a
|
||||||
|
// address, [scheme://]address:port or a filename. The address part is checked
|
||||||
|
// and in case of filename a resolv.conf like file is (assumed) and parsed and
|
||||||
|
// the nameservers found are returned.
|
||||||
|
func HostPortOrFile(s ...string) ([]string, error) {
|
||||||
|
var servers []string
|
||||||
|
for _, h := range s {
|
||||||
|
|
||||||
|
trans, host := Transport(h)
|
||||||
|
|
||||||
|
addr, _, err := net.SplitHostPort(host)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Parse didn't work, it is not a addr:port combo
|
||||||
|
hostNoZone := stripZone(host)
|
||||||
|
if net.ParseIP(hostNoZone) == nil {
|
||||||
|
ss, err := tryFile(host)
|
||||||
|
if err == nil {
|
||||||
|
servers = append(servers, ss...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return servers, fmt.Errorf("not an IP address or file: %q", host)
|
||||||
|
}
|
||||||
|
var ss string
|
||||||
|
switch trans {
|
||||||
|
case transport.DNS:
|
||||||
|
ss = net.JoinHostPort(host, transport.Port)
|
||||||
|
case transport.TLS:
|
||||||
|
ss = transport.TLS + "://" + net.JoinHostPort(host, transport.TLSPort)
|
||||||
|
case transport.GRPC:
|
||||||
|
ss = transport.GRPC + "://" + net.JoinHostPort(host, transport.GRPCPort)
|
||||||
|
case transport.HTTPS:
|
||||||
|
ss = transport.HTTPS + "://" + net.JoinHostPort(host, transport.HTTPSPort)
|
||||||
|
}
|
||||||
|
servers = append(servers, ss)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.ParseIP(stripZone(addr)) == nil {
|
||||||
|
ss, err := tryFile(host)
|
||||||
|
if err == nil {
|
||||||
|
servers = append(servers, ss...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return servers, fmt.Errorf("not an IP address or file: %q", host)
|
||||||
|
}
|
||||||
|
servers = append(servers, h)
|
||||||
|
}
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return servers, fmt.Errorf("no nameservers found")
|
||||||
|
}
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to open this is a file first.
|
||||||
|
func tryFile(s string) ([]string, error) {
|
||||||
|
c, err := dns.ClientConfigFromFile(s)
|
||||||
|
if err == os.ErrNotExist {
|
||||||
|
return nil, fmt.Errorf("failed to open file %q: %q", s, err)
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
servers := []string{}
|
||||||
|
for _, s := range c.Servers {
|
||||||
|
servers = append(servers, net.JoinHostPort(s, c.Port))
|
||||||
|
}
|
||||||
|
return servers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostPort will check if the host part is a valid IP address, if the
|
||||||
|
// IP address is valid, but no port is found, defaultPort is added.
|
||||||
|
func HostPort(s, defaultPort string) (string, error) {
|
||||||
|
addr, port, err := net.SplitHostPort(s)
|
||||||
|
if port == "" {
|
||||||
|
port = defaultPort
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if net.ParseIP(s) == nil {
|
||||||
|
return "", fmt.Errorf("must specify an IP address: `%s'", s)
|
||||||
|
}
|
||||||
|
return net.JoinHostPort(s, port), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if net.ParseIP(addr) == nil {
|
||||||
|
return "", fmt.Errorf("must specify an IP address: `%s'", addr)
|
||||||
|
}
|
||||||
|
return net.JoinHostPort(addr, port), nil
|
||||||
|
}
|
49
vendor/github.com/coredns/coredns/plugin/pkg/parse/parse.go
generated
vendored
Normal file
49
vendor/github.com/coredns/coredns/plugin/pkg/parse/parse.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Package parse contains functions that can be used in the setup code for plugins.
|
||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transfer parses transfer statements: 'transfer [to|from] [address...]'.
|
||||||
|
func Transfer(c *caddy.Controller, secondary bool) (tos, froms []string, err error) {
|
||||||
|
if !c.NextArg() {
|
||||||
|
return nil, nil, c.ArgErr()
|
||||||
|
}
|
||||||
|
value := c.Val()
|
||||||
|
switch value {
|
||||||
|
case "to":
|
||||||
|
tos = c.RemainingArgs()
|
||||||
|
for i := range tos {
|
||||||
|
if tos[i] != "*" {
|
||||||
|
normalized, err := HostPort(tos[i], transport.Port)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
tos[i] = normalized
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "from":
|
||||||
|
if !secondary {
|
||||||
|
return nil, nil, fmt.Errorf("can't use `transfer from` when not being a secondary")
|
||||||
|
}
|
||||||
|
froms = c.RemainingArgs()
|
||||||
|
for i := range froms {
|
||||||
|
if froms[i] != "*" {
|
||||||
|
normalized, err := HostPort(froms[i], transport.Port)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
froms[i] = normalized
|
||||||
|
} else {
|
||||||
|
return nil, nil, fmt.Errorf("can't use '*' in transfer from")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
33
vendor/github.com/coredns/coredns/plugin/pkg/parse/transport.go
generated
vendored
Normal file
33
vendor/github.com/coredns/coredns/plugin/pkg/parse/transport.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transport returns the transport defined in s and a string where the
|
||||||
|
// transport prefix is removed (if there was any). If no transport is defined
|
||||||
|
// we default to TransportDNS
|
||||||
|
func Transport(s string) (trans string, addr string) {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(s, transport.TLS+"://"):
|
||||||
|
s = s[len(transport.TLS+"://"):]
|
||||||
|
return transport.TLS, s
|
||||||
|
|
||||||
|
case strings.HasPrefix(s, transport.DNS+"://"):
|
||||||
|
s = s[len(transport.DNS+"://"):]
|
||||||
|
return transport.DNS, s
|
||||||
|
|
||||||
|
case strings.HasPrefix(s, transport.GRPC+"://"):
|
||||||
|
s = s[len(transport.GRPC+"://"):]
|
||||||
|
return transport.GRPC, s
|
||||||
|
|
||||||
|
case strings.HasPrefix(s, transport.HTTPS+"://"):
|
||||||
|
s = s[len(transport.HTTPS+"://"):]
|
||||||
|
|
||||||
|
return transport.HTTPS, s
|
||||||
|
}
|
||||||
|
|
||||||
|
return transport.DNS, s
|
||||||
|
}
|
15
vendor/github.com/coredns/coredns/plugin/pkg/rcode/rcode.go
generated
vendored
Normal file
15
vendor/github.com/coredns/coredns/plugin/pkg/rcode/rcode.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package rcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ToString convert the rcode to the official DNS string, or to "RCODE"+value if the RCODE value is unknown.
|
||||||
|
func ToString(rcode int) string {
|
||||||
|
if str, ok := dns.RcodeToString[rcode]; ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return "RCODE" + strconv.Itoa(rcode)
|
||||||
|
}
|
61
vendor/github.com/coredns/coredns/plugin/pkg/response/classify.go
generated
vendored
Normal file
61
vendor/github.com/coredns/coredns/plugin/pkg/response/classify.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Class holds sets of Types
|
||||||
|
type Class int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// All is a meta class encompassing all the classes.
|
||||||
|
All Class = iota
|
||||||
|
// Success is a class for a successful response.
|
||||||
|
Success
|
||||||
|
// Denial is a class for denying existence (NXDOMAIN, or a nodata: type does not exist)
|
||||||
|
Denial
|
||||||
|
// Error is a class for errors, right now defined as not Success and not Denial
|
||||||
|
Error
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c Class) String() string {
|
||||||
|
switch c {
|
||||||
|
case All:
|
||||||
|
return "all"
|
||||||
|
case Success:
|
||||||
|
return "success"
|
||||||
|
case Denial:
|
||||||
|
return "denial"
|
||||||
|
case Error:
|
||||||
|
return "error"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClassFromString returns the class from the string s. If not class matches
|
||||||
|
// the All class and an error are returned
|
||||||
|
func ClassFromString(s string) (Class, error) {
|
||||||
|
switch s {
|
||||||
|
case "all":
|
||||||
|
return All, nil
|
||||||
|
case "success":
|
||||||
|
return Success, nil
|
||||||
|
case "denial":
|
||||||
|
return Denial, nil
|
||||||
|
case "error":
|
||||||
|
return Error, nil
|
||||||
|
}
|
||||||
|
return All, fmt.Errorf("invalid Class: %s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classify classifies the Type t, it returns its Class.
|
||||||
|
func Classify(t Type) Class {
|
||||||
|
switch t {
|
||||||
|
case NoError, Delegation:
|
||||||
|
return Success
|
||||||
|
case NameError, NoData:
|
||||||
|
return Denial
|
||||||
|
case OtherError:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return Error
|
||||||
|
}
|
||||||
|
}
|
151
vendor/github.com/coredns/coredns/plugin/pkg/response/typify.go
generated
vendored
Normal file
151
vendor/github.com/coredns/coredns/plugin/pkg/response/typify.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type is the type of the message.
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// NoError indicates a positive reply
|
||||||
|
NoError Type = iota
|
||||||
|
// NameError is a NXDOMAIN in header, SOA in auth.
|
||||||
|
NameError
|
||||||
|
// ServerError is a set of errors we want to cache, for now it contains SERVFAIL and NOTIMPL.
|
||||||
|
ServerError
|
||||||
|
// NoData indicates name found, but not the type: NOERROR in header, SOA in auth.
|
||||||
|
NoData
|
||||||
|
// Delegation is a msg with a pointer to another nameserver: NOERROR in header, NS in auth, optionally fluff in additional (not checked).
|
||||||
|
Delegation
|
||||||
|
// Meta indicates a meta message, NOTIFY, or a transfer: qType is IXFR or AXFR.
|
||||||
|
Meta
|
||||||
|
// Update is an dynamic update message.
|
||||||
|
Update
|
||||||
|
// OtherError indicates any other error: don't cache these.
|
||||||
|
OtherError
|
||||||
|
)
|
||||||
|
|
||||||
|
var toString = map[Type]string{
|
||||||
|
NoError: "NOERROR",
|
||||||
|
NameError: "NXDOMAIN",
|
||||||
|
ServerError: "SERVERERROR",
|
||||||
|
NoData: "NODATA",
|
||||||
|
Delegation: "DELEGATION",
|
||||||
|
Meta: "META",
|
||||||
|
Update: "UPDATE",
|
||||||
|
OtherError: "OTHERERROR",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Type) String() string { return toString[t] }
|
||||||
|
|
||||||
|
// TypeFromString returns the type from the string s. If not type matches
|
||||||
|
// the OtherError type and an error are returned.
|
||||||
|
func TypeFromString(s string) (Type, error) {
|
||||||
|
for t, str := range toString {
|
||||||
|
if s == str {
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NoError, fmt.Errorf("invalid Type: %s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Typify classifies a message, it returns the Type.
|
||||||
|
func Typify(m *dns.Msg, t time.Time) (Type, *dns.OPT) {
|
||||||
|
if m == nil {
|
||||||
|
return OtherError, nil
|
||||||
|
}
|
||||||
|
opt := m.IsEdns0()
|
||||||
|
do := false
|
||||||
|
if opt != nil {
|
||||||
|
do = opt.Do()
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Opcode == dns.OpcodeUpdate {
|
||||||
|
return Update, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check transfer and update first
|
||||||
|
if m.Opcode == dns.OpcodeNotify {
|
||||||
|
return Meta, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.Question) > 0 {
|
||||||
|
if m.Question[0].Qtype == dns.TypeAXFR || m.Question[0].Qtype == dns.TypeIXFR {
|
||||||
|
return Meta, opt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If our message contains any expired sigs and we care about that, we should return expired
|
||||||
|
if do {
|
||||||
|
if expired := typifyExpired(m, t); expired {
|
||||||
|
return OtherError, opt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.Answer) > 0 && m.Rcode == dns.RcodeSuccess {
|
||||||
|
return NoError, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
soa := false
|
||||||
|
ns := 0
|
||||||
|
for _, r := range m.Ns {
|
||||||
|
if r.Header().Rrtype == dns.TypeSOA {
|
||||||
|
soa = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r.Header().Rrtype == dns.TypeNS {
|
||||||
|
ns++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if soa && m.Rcode == dns.RcodeSuccess {
|
||||||
|
return NoData, opt
|
||||||
|
}
|
||||||
|
if soa && m.Rcode == dns.RcodeNameError {
|
||||||
|
return NameError, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Rcode == dns.RcodeServerFailure || m.Rcode == dns.RcodeNotImplemented {
|
||||||
|
return ServerError, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
if ns > 0 && m.Rcode == dns.RcodeSuccess {
|
||||||
|
return Delegation, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Rcode == dns.RcodeSuccess {
|
||||||
|
return NoError, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
return OtherError, opt
|
||||||
|
}
|
||||||
|
|
||||||
|
func typifyExpired(m *dns.Msg, t time.Time) bool {
|
||||||
|
if expired := typifyExpiredRRSIG(m.Answer, t); expired {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if expired := typifyExpiredRRSIG(m.Ns, t); expired {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if expired := typifyExpiredRRSIG(m.Extra, t); expired {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func typifyExpiredRRSIG(rrs []dns.RR, t time.Time) bool {
|
||||||
|
for _, r := range rrs {
|
||||||
|
if r.Header().Rrtype != dns.TypeRRSIG {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ok := r.(*dns.RRSIG).ValidityPeriod(t)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
37
vendor/github.com/coredns/coredns/plugin/pkg/reuseport/listen_go111.go
generated
vendored
Normal file
37
vendor/github.com/coredns/coredns/plugin/pkg/reuseport/listen_go111.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// +build go1.11
|
||||||
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd
|
||||||
|
|
||||||
|
package reuseport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/log"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func control(network, address string, c syscall.RawConn) error {
|
||||||
|
c.Control(func(fd uintptr) {
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
|
||||||
|
log.Warningf("Failed to set SO_REUSEPORT on socket: %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen announces on the local network address. See net.Listen for more information.
|
||||||
|
// If SO_REUSEPORT is available it will be set on the socket.
|
||||||
|
func Listen(network, addr string) (net.Listener, error) {
|
||||||
|
lc := net.ListenConfig{Control: control}
|
||||||
|
return lc.Listen(context.Background(), network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenPacket announces on the local network address. See net.ListenPacket for more information.
|
||||||
|
// If SO_REUSEPORT is available it will be set on the socket.
|
||||||
|
func ListenPacket(network, addr string) (net.PacketConn, error) {
|
||||||
|
lc := net.ListenConfig{Control: control}
|
||||||
|
return lc.ListenPacket(context.Background(), network, addr)
|
||||||
|
}
|
13
vendor/github.com/coredns/coredns/plugin/pkg/reuseport/listen_go_not111.go
generated
vendored
Normal file
13
vendor/github.com/coredns/coredns/plugin/pkg/reuseport/listen_go_not111.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// +build !go1.11 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
|
||||||
|
|
||||||
|
package reuseport
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
// Listen is a wrapper around net.Listen.
|
||||||
|
func Listen(network, addr string) (net.Listener, error) { return net.Listen(network, addr) }
|
||||||
|
|
||||||
|
// ListenPacket is a wrapper around net.ListenPacket.
|
||||||
|
func ListenPacket(network, addr string) (net.PacketConn, error) {
|
||||||
|
return net.ListenPacket(network, addr)
|
||||||
|
}
|
12
vendor/github.com/coredns/coredns/plugin/pkg/trace/trace.go
generated
vendored
Normal file
12
vendor/github.com/coredns/coredns/plugin/pkg/trace/trace.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coredns/coredns/plugin"
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Trace holds the tracer and endpoint info
|
||||||
|
type Trace interface {
|
||||||
|
plugin.Handler
|
||||||
|
Tracer() ot.Tracer
|
||||||
|
}
|
21
vendor/github.com/coredns/coredns/plugin/pkg/transport/transport.go
generated
vendored
Normal file
21
vendor/github.com/coredns/coredns/plugin/pkg/transport/transport.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
// These transports are supported by CoreDNS.
|
||||||
|
const (
|
||||||
|
DNS = "dns"
|
||||||
|
TLS = "tls"
|
||||||
|
GRPC = "grpc"
|
||||||
|
HTTPS = "https"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Port numbers for the various transports.
|
||||||
|
const (
|
||||||
|
// Port is the default port for DNS
|
||||||
|
Port = "53"
|
||||||
|
// TLSPort is the default port for DNS-over-TLS.
|
||||||
|
TLSPort = "853"
|
||||||
|
// GRPCPort is the default port for DNS-over-gRPC.
|
||||||
|
GRPCPort = "443"
|
||||||
|
// HTTPSPort is the default port for DNS-over-HTTPS.
|
||||||
|
HTTPSPort = "443"
|
||||||
|
)
|
46
vendor/github.com/coredns/coredns/plugin/pkg/uniq/uniq.go
generated
vendored
Normal file
46
vendor/github.com/coredns/coredns/plugin/pkg/uniq/uniq.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Package uniq keeps track of "thing" that are either "todo" or "done". Multiple
|
||||||
|
// identical events will only be processed once.
|
||||||
|
package uniq
|
||||||
|
|
||||||
|
// U keeps track of item to be done.
|
||||||
|
type U struct {
|
||||||
|
u map[string]item
|
||||||
|
}
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
state int // either todo or done
|
||||||
|
f func() error // function to be executed.
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new initialized U.
|
||||||
|
func New() U { return U{u: make(map[string]item)} }
|
||||||
|
|
||||||
|
// Set sets function f in U under key. If the key already exists it is not overwritten.
|
||||||
|
func (u U) Set(key string, f func() error) {
|
||||||
|
if _, ok := u.u[key]; ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
u.u[key] = item{todo, f}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset removes the key.
|
||||||
|
func (u U) Unset(key string) {
|
||||||
|
delete(u.u, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEach iterates over u and executes f for each element that is 'todo' and sets it to 'done'.
|
||||||
|
func (u U) ForEach() error {
|
||||||
|
for k, v := range u.u {
|
||||||
|
if v.state == todo {
|
||||||
|
v.f()
|
||||||
|
}
|
||||||
|
v.state = done
|
||||||
|
u.u[k] = v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
todo = 1
|
||||||
|
done = 2
|
||||||
|
)
|
109
vendor/github.com/coredns/coredns/plugin/plugin.go
generated
vendored
Normal file
109
vendor/github.com/coredns/coredns/plugin/plugin.go
generated
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Package plugin provides some types and functions common among plugin.
|
||||||
|
package plugin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Plugin is a middle layer which represents the traditional
|
||||||
|
// idea of plugin: it chains one Handler to the next by being
|
||||||
|
// passed the next Handler in the chain.
|
||||||
|
Plugin func(Handler) Handler
|
||||||
|
|
||||||
|
// Handler is like dns.Handler except ServeDNS may return an rcode
|
||||||
|
// and/or error.
|
||||||
|
//
|
||||||
|
// If ServeDNS writes to the response body, it should return a status
|
||||||
|
// code. CoreDNS assumes *no* reply has yet been written if the status
|
||||||
|
// code is one of the following:
|
||||||
|
//
|
||||||
|
// * SERVFAIL (dns.RcodeServerFailure)
|
||||||
|
//
|
||||||
|
// * REFUSED (dns.RecodeRefused)
|
||||||
|
//
|
||||||
|
// * FORMERR (dns.RcodeFormatError)
|
||||||
|
//
|
||||||
|
// * NOTIMP (dns.RcodeNotImplemented)
|
||||||
|
//
|
||||||
|
// All other response codes signal other handlers above it that the
|
||||||
|
// response message is already written, and that they should not write
|
||||||
|
// to it also.
|
||||||
|
//
|
||||||
|
// If ServeDNS encounters an error, it should return the error value
|
||||||
|
// so it can be logged by designated error-handling plugin.
|
||||||
|
//
|
||||||
|
// If writing a response after calling another ServeDNS method, the
|
||||||
|
// returned rcode SHOULD be used when writing the response.
|
||||||
|
//
|
||||||
|
// If handling errors after calling another ServeDNS method, the
|
||||||
|
// returned error value SHOULD be logged or handled accordingly.
|
||||||
|
//
|
||||||
|
// Otherwise, return values should be propagated down the plugin
|
||||||
|
// chain by returning them unchanged.
|
||||||
|
Handler interface {
|
||||||
|
ServeDNS(context.Context, dns.ResponseWriter, *dns.Msg) (int, error)
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerFunc is a convenience type like dns.HandlerFunc, except
|
||||||
|
// ServeDNS returns an rcode and an error. See Handler
|
||||||
|
// documentation for more information.
|
||||||
|
HandlerFunc func(context.Context, dns.ResponseWriter, *dns.Msg) (int, error)
|
||||||
|
)
|
||||||
|
|
||||||
|
// ServeDNS implements the Handler interface.
|
||||||
|
func (f HandlerFunc) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||||
|
return f(ctx, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name implements the Handler interface.
|
||||||
|
func (f HandlerFunc) Name() string { return "handlerfunc" }
|
||||||
|
|
||||||
|
// Error returns err with 'plugin/name: ' prefixed to it.
|
||||||
|
func Error(name string, err error) error { return fmt.Errorf("%s/%s: %s", "plugin", name, err) }
|
||||||
|
|
||||||
|
// NextOrFailure calls next.ServeDNS when next is not nil, otherwise it will return, a ServerFailure and a nil error.
|
||||||
|
func NextOrFailure(name string, next Handler, ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) { // nolint: golint
|
||||||
|
if next != nil {
|
||||||
|
if span := ot.SpanFromContext(ctx); span != nil {
|
||||||
|
child := span.Tracer().StartSpan(next.Name(), ot.ChildOf(span.Context()))
|
||||||
|
defer child.Finish()
|
||||||
|
ctx = ot.ContextWithSpan(ctx, child)
|
||||||
|
}
|
||||||
|
return next.ServeDNS(ctx, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dns.RcodeServerFailure, Error(name, errors.New("no next plugin found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientWrite returns true if the response has been written to the client.
|
||||||
|
// Each plugin to adhere to this protocol.
|
||||||
|
func ClientWrite(rcode int) bool {
|
||||||
|
switch rcode {
|
||||||
|
case dns.RcodeServerFailure:
|
||||||
|
fallthrough
|
||||||
|
case dns.RcodeRefused:
|
||||||
|
fallthrough
|
||||||
|
case dns.RcodeFormatError:
|
||||||
|
fallthrough
|
||||||
|
case dns.RcodeNotImplemented:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace is the namespace used for the metrics.
|
||||||
|
const Namespace = "coredns"
|
||||||
|
|
||||||
|
// TimeBuckets is based on Prometheus client_golang prometheus.DefBuckets
|
||||||
|
var TimeBuckets = prometheus.ExponentialBuckets(0.00025, 2, 16) // from 0.25ms to 8 seconds
|
||||||
|
|
||||||
|
// ErrOnce is returned when a plugin doesn't support multiple setups per server.
|
||||||
|
var ErrOnce = errors.New("this plugin can only be used once per Server Block")
|
11
vendor/github.com/coredns/coredns/plugin/register.go
generated
vendored
Normal file
11
vendor/github.com/coredns/coredns/plugin/register.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
import "github.com/caddyserver/caddy"
|
||||||
|
|
||||||
|
// Register registers your plugin with CoreDNS and allows it to be called when the server is running.
|
||||||
|
func Register(name string, action caddy.SetupFunc) {
|
||||||
|
caddy.RegisterPlugin(name, caddy.Plugin{
|
||||||
|
ServerType: "dns",
|
||||||
|
Action: action,
|
||||||
|
})
|
||||||
|
}
|
2
vendor/github.com/coredns/coredns/plugin/test/doc.go
generated
vendored
Normal file
2
vendor/github.com/coredns/coredns/plugin/test/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// Package test contains helper functions for writing plugin tests.
|
||||||
|
package test
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user