From 2da1c62c691561730e5087fb65750eadca05c6b1 Mon Sep 17 00:00:00 2001 From: Vikizhao <49028598+vikizhao156@users.noreply.github.com> Date: Fri, 22 Sep 2023 09:32:02 +0800 Subject: [PATCH] feat: support KnativeIngress (#524) --- go.mod | 61 +- go.sum | 285 +++---- .../templates/controller-clusterrole.yaml | 7 + pkg/bootstrap/server.go | 18 +- pkg/config/constants/constants.go | 4 + pkg/ingress/config/kingress_config.go | 552 +++++++++++++ pkg/ingress/config/kingress_config_test.go | 481 +++++++++++ pkg/ingress/kube/common/controller.go | 24 + pkg/ingress/kube/kingress/controller.go | 751 ++++++++++++++++++ pkg/ingress/kube/kingress/controller_test.go | 604 ++++++++++++++ pkg/ingress/kube/kingress/resources/doc.go | 19 + .../kingress/resources/virtual_service.go | 148 ++++ .../resources/virtual_service_test.go | 258 ++++++ pkg/ingress/kube/kingress/status.go | 127 +++ pkg/ingress/translation/translation.go | 204 +++++ pkg/kube/client.go | 106 ++- 16 files changed, 3431 insertions(+), 218 deletions(-) create mode 100644 pkg/ingress/config/kingress_config.go create mode 100644 pkg/ingress/config/kingress_config_test.go create mode 100644 pkg/ingress/kube/kingress/controller.go create mode 100644 pkg/ingress/kube/kingress/controller_test.go create mode 100644 pkg/ingress/kube/kingress/resources/doc.go create mode 100644 pkg/ingress/kube/kingress/resources/virtual_service.go create mode 100644 pkg/ingress/kube/kingress/resources/virtual_service_test.go create mode 100644 pkg/ingress/kube/kingress/status.go create mode 100644 pkg/ingress/translation/translation.go diff --git a/go.mod b/go.mod index 341fcea4b..8de5c2683 100644 --- a/go.mod +++ b/go.mod @@ -21,16 +21,13 @@ require ( github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5 github.com/dubbogo/gost v1.13.1 github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 - github.com/evanphx/json-patch/v5 v5.6.0 github.com/gogo/protobuf v1.3.2 github.com/golang/protobuf v1.5.2 github.com/google/go-cmp v0.5.9 - github.com/google/yamlfmt v0.10.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/hashicorp/consul/api v1.23.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hudl/fargo v1.4.0 - github.com/kylelemons/godebug v1.1.0 github.com/nacos-group/nacos-sdk-go v1.0.8 github.com/nacos-group/nacos-sdk-go/v2 v2.1.2 github.com/pkg/errors v0.9.1 @@ -41,23 +38,22 @@ require ( google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.0 gopkg.in/yaml.v2 v2.4.0 - helm.sh/helm/v3 v3.7.1 istio.io/api v0.0.0-20211122181927-8da52c66ff23 istio.io/client-go v1.12.0-rc.1.0.20211118171212-b744b6f111e4 istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67 istio.io/istio v0.0.0 istio.io/pkg v0.0.0-20211115195056-e379f31ee62a - k8s.io/api v0.22.2 - k8s.io/apimachinery v0.22.2 + k8s.io/api v0.22.5 + k8s.io/apimachinery v0.22.5 k8s.io/cli-runtime v0.22.2 - k8s.io/client-go v0.22.2 + k8s.io/client-go v0.22.5 k8s.io/kubectl v0.22.2 sigs.k8s.io/controller-runtime v0.10.2 sigs.k8s.io/yaml v1.3.0 ) require ( - cloud.google.com/go v0.97.0 // indirect + cloud.google.com/go v0.98.0 // indirect cloud.google.com/go/logging v1.4.2 // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect @@ -91,6 +87,7 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/clbanning/mxj v1.8.4 // indirect + github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect github.com/cncf/xds/go v0.0.0-20220520190051-1e77728a1eaa // indirect github.com/containerd/containerd v1.5.7 // indirect github.com/containerd/continuity v0.1.0 // indirect @@ -116,16 +113,15 @@ require ( github.com/go-errors/errors v1.0.1 // indirect github.com/go-kit/log v0.1.0 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect - github.com/go-logr/logr v0.4.0 // indirect + github.com/go-logr/logr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.5 // indirect - github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-openapi/swag v0.19.15 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.4.8 // indirect github.com/golang-jwt/jwt/v4 v4.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/snappy v0.0.3 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-containerregistry v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -153,9 +149,7 @@ require ( github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.13.0 // indirect - github.com/kr/pretty v0.3.0 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/klauspost/compress v1.13.6 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lestrrat-go/backoff/v2 v2.0.7 // indirect @@ -168,7 +162,7 @@ require ( github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect github.com/lib/pq v1.10.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect @@ -200,7 +194,6 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/statsd_exporter v0.21.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.6.1 // indirect github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc // indirect github.com/russross/blackfriday v1.5.2 // indirect github.com/shopspring/decimal v1.2.0 // indirect @@ -230,9 +223,9 @@ require ( gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gomodules.xyz/jsonpatch/v3 v3.0.1 // indirect gomodules.xyz/orderedmap v0.1.0 // indirect - google.golang.org/api v0.59.0 // indirect + google.golang.org/api v0.61.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a // indirect + google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12 // indirect gopkg.in/gcfg.v1 v1.2.3 // indirect gopkg.in/gorp.v1 v1.7.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -241,11 +234,10 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.22.2 // indirect k8s.io/apiserver v0.22.2 // indirect k8s.io/component-base v0.22.2 // indirect - k8s.io/klog/v2 v2.10.0 // indirect - k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b // indirect + k8s.io/klog/v2 v2.40.1 // indirect + k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect oras.land/oras-go v0.4.0 // indirect sigs.k8s.io/gateway-api v0.4.0 // indirect @@ -266,3 +258,30 @@ replace istio.io/pkg => ./external/pkg replace istio.io/client-go => ./external/client-go replace istio.io/istio => ./external/istio + +replace ( + github.com/go-logr/logr => github.com/go-logr/logr v0.4.0 + k8s.io/api => k8s.io/api v0.22.2 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.22.2 + k8s.io/apimachinery => k8s.io/apimachinery v0.22.2 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.22.2 + k8s.io/client-go => k8s.io/client-go v0.22.2 + k8s.io/component-base => k8s.io/component-base v0.22.2 + k8s.io/klog/v2 => k8s.io/klog/v2 v2.10.0 + k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b // indirect + k8s.io/kubectl => k8s.io/kubectl v0.22.2 + k8s.io/utils => k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect + sigs.k8s.io/gateway-api => sigs.k8s.io/gateway-api v0.4.0 // indirect + sigs.k8s.io/kustomize/api => sigs.k8s.io/kustomize/api v0.8.11 // indirect + sigs.k8s.io/kustomize/kyaml => sigs.k8s.io/kustomize/kyaml v0.11.0 // indirect +) + +require ( + github.com/evanphx/json-patch/v5 v5.6.0 + github.com/google/yamlfmt v0.10.0 + github.com/kylelemons/godebug v1.1.0 + helm.sh/helm/v3 v3.7.1 + k8s.io/apiextensions-apiserver v0.25.4 + knative.dev/networking v0.0.0-20220302134042-e8b2eb995165 + knative.dev/pkg v0.0.0-20220301181942-2fdd5f232e77 +) diff --git a/go.sum b/go.sum index 71792e436..354f1dee0 100644 --- a/go.sum +++ b/go.sum @@ -27,8 +27,9 @@ cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWc cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0 h1:w6LozQJyDDEyhf64Uusu1LCcnLt0I1VMLiJC2kV+eXk= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -49,8 +50,11 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.18.2/go.mod h1:AiIj7BWXyhO5gGVmYJ+S8tbkCx3yb0IMjua8Aw4naVM= +contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= contrib.go.opencensus.io/exporter/prometheus v0.4.0 h1:0QfIkj9z/iVZgK31D9H9ohjjIDApI2GOPScCKwxedbs= contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= +contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= @@ -60,43 +64,29 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/AdaLogics/go-fuzz-headers v0.0.0-20210929163055-e81b3f25be97/go.mod h1:WpB7kf89yJUETZxQnP1kgYPNwlT2jjdDYUCoxVggM3g= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest v0.11.20/go.mod h1:o3tqFY+QR40VOlk+pV4d77mORO64jOXSgEnPQgLK6JY= github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/adal v0.9.15/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= -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.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -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.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -145,11 +135,8 @@ github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:m github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RageCage64/multilinediff v0.2.0 h1:yNSpSF5NXIrmo6bRIgO4Q0g7SXqFD4j/WEcBE+BdCFY= @@ -157,15 +144,17 @@ github.com/RageCage64/multilinediff v0.2.0/go.mod h1:pKr+KLgP0gvRzA+yv0/IUaYQuBY github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agiledragon/gomonkey/v2 v2.9.0 h1:PDiKKybR596O6FHW+RVSG0Z7uGCBNbmbUXh3uCNQ7Hc= github.com/agiledragon/gomonkey/v2 v2.9.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= -github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8= +github.com/alecthomas/jsonschema v0.0.0-20180308105923-f2c93856175a/go.mod h1:qpebaTNSsyUn5rPSJMsfqEtDw71TTggXM6stUDI16HA= 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= @@ -177,7 +166,6 @@ github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -190,7 +178,6 @@ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= @@ -215,11 +202,13 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/braydonk/yaml v0.7.0 h1:ySkqO7r0MGoCNhiRJqE0Xe9yhINMyvOAB3nFjgyJn2k= github.com/braydonk/yaml v0.7.0/go.mod h1:hcm3h581tudlirk8XEUPDBAimBPbmnL0Y45hCRl47N4= @@ -236,6 +225,7 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= @@ -394,7 +384,6 @@ github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+ github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -423,6 +412,9 @@ github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27N github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-gk v0.0.0-20140819190930-201884a44051/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= +github.com/dgryski/go-lttb v0.0.0-20180810165845-318fcdf10a77/go.mod h1:Va5MyIzkU0rAM92tn3hb3Anb7oz7KcnixF49+2wOMe4= github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3/go.mod h1:gt38b7cvVKazi5XkHvINNytZXgTEntyhtyM3HQz46Nk= github.com/distribution/distribution/v3 v3.0.0-20210926092439-1563384b69df h1:zafDqOsnugdrReF9Pe0wybnfFtEIaegSyHNIvnwKPVk= github.com/distribution/distribution/v3 v3.0.0-20210926092439-1563384b69df/go.mod h1:ZDZib/BOniVWcXcsy0voU8gR00znhe5VJm47d3H2Y5g= @@ -441,12 +433,10 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6Uezg github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= -github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5 h1:XoR8SSVziXe698dt4uZYDfsmHpKLemqAgFyndQsq5Kw= github.com/dubbogo/go-zookeeper v1.0.4-0.20211212162352-f9d2183d89d5/go.mod h1:fn6n2CAEer3novYgk9ULLwAjuV8/g4DdC2ENwRb6E+c= @@ -454,6 +444,7 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:Htrtb github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dvyukov/go-fuzz v0.0.0-20210914135545-4980593459a1/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -464,7 +455,6 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -491,6 +481,7 @@ github.com/florianl/go-nflog/v2 v2.0.1/go.mod h1:g+SOgM/SuePn9bvS/eo3Ild7J71nSb2 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2 h1:cZqz+yOJ/R64LcKjNQOdARott/jP7BnUQ9Ah7KaZCvw= @@ -508,12 +499,9 @@ github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui72 github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -529,64 +517,26 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= -github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= -github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= -github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= -github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= -github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= -github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= -github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= -github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= -github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= -github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= -github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= -github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= -github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= -github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= -github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= -github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= -github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= @@ -596,6 +546,7 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8Wd github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/flect v0.2.3/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= +github.com/gobuffalo/flect v0.2.4/go.mod h1:1ZyCLIbg0YD7sDkzvFdPoOydPtD8y9JQnrOROolUcM8= github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gqc= github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM= @@ -650,7 +601,6 @@ github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71 github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -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.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -670,11 +620,20 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k= github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/diff v0.0.0-20181124234638-500114f11e71/go.mod h1:22dM4PLscQl+Nzf64qNBurVJvfyvZELT0iRW2l/NN70= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2/go.mod h1:pDgmNM6seYpwvPos3q+zxlXMsbve6mOIPucUnUOrI7Y= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/mathext v0.0.0-20181121095525-8a4bf007ea55/go.mod h1:fmo8aiSEWkJeiGXUJf+sPvuDgEFgqIoZSs843ePKrGg= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -696,11 +655,13 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-containerregistry v0.6.0 h1:niQ+8XD//kKgArIFwDVBXsWVWbde16LPdHMyNwSC8h4= github.com/google/go-containerregistry v0.6.0/go.mod h1:euCCtNbZ6tKqi1E72vwDj2xZcN5ttKpZLfa/wSo5iLw= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/mako v0.0.0-20190821191249-122f8dcef9e3/go.mod h1:YzLcVlL+NqWnmUEPuhS1LxDDwGO9WNbVlEXaF4IH35g= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -737,14 +698,11 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -756,8 +714,9 @@ github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= @@ -808,6 +767,7 @@ github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0S github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= @@ -841,9 +801,16 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/tdigest v0.0.0-20180711151920-a7d76c6f093a/go.mod h1:9GkyshztGufsdPQWjH+ifgnIr3xNUL5syI70g2dzU1o= github.com/istio/viper v1.3.3-0.20190515210538-2789fed3109c/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= @@ -894,6 +861,7 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/karrick/godirwalk v1.15.8 h1:7+rWAZPn9zuRxaIqqT8Ohs2Q2Ac0msBqwRdxNCr2VVs= github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -901,8 +869,9 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.0 h1:2T7tUoQrQT+fQWdaY5rjWztFGAFwbGD04iPJg90ZiOs= github.com/klauspost/compress v1.13.0/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -962,14 +931,13 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= @@ -1032,6 +1000,7 @@ github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqA github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.17/go.mod h1:WgzbA6oji13JREwiNsRDNfl7jYdPnmz+VEuLrA+/48M= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= @@ -1072,8 +1041,6 @@ github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= -github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1129,8 +1096,9 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= 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= @@ -1184,6 +1152,7 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.3.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -1199,6 +1168,7 @@ github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoU github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.6.1+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-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1266,7 +1236,9 @@ github.com/prometheus/prometheus v2.5.0+incompatible h1:7QPitgO2kOFG8ecuRn9O/4L9 github.com/prometheus/prometheus v2.5.0+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8= github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= +github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1276,6 +1248,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc h1:BD7uZqkN8CpjJtN/tScAKiccBikU4dlqe/gNrkRaPY4= github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc/go.mod h1:HFLT6i9iR4QBOF5rdCyjddC9t59ArqWJV2xx+jwcCMo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= @@ -1359,7 +1332,6 @@ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSW github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -1370,6 +1342,7 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1397,20 +1370,21 @@ github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cb github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 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/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 h1:kF/7m/ZU+0D4Jj5eZ41Zm3IH/J8OElK1Qtd7tVKAwLk= github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3/go.mod h1:QDlpd3qS71vYtakd2hmdpqhJ9nwv6mD6A30bQ1BPBFE= +github.com/tsenart/go-tsz v0.0.0-20180814232043-cdeb9e1e981e/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo= +github.com/tsenart/vegeta/v12 v12.8.4/go.mod h1:ZiJtwLn/9M4fTPdMY7bdbIeyNeFVE8/AHbWFqCsUuho= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 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/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= @@ -1423,6 +1397,9 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1442,6 +1419,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= @@ -1468,9 +1446,6 @@ go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0/go.mod h1:FAwse6Zlm5v4tEWZaTjmNhe17Int4Ox go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0-alpha.0/go.mod h1:tsKetYpt980ZTpzl/gb+UOJj9RkIyCb1u4wjzMg90BQ= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1505,6 +1480,7 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= @@ -1534,34 +1510,34 @@ golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1600,16 +1576,14 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/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-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1622,7 +1596,6 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/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= @@ -1666,7 +1639,6 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -1676,8 +1648,12 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1716,7 +1692,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/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-20180823144017-11551d06cbcc/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= @@ -1727,12 +1702,10 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h 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-20181205085412-a5c9d58dba9a/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-20190222072716-a9d3bda3a223/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-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/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= @@ -1815,7 +1788,6 @@ golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1842,8 +1814,12 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1852,9 +1828,9 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1863,6 +1839,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1873,16 +1850,15 @@ golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/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-20181030000716-a0a13e073c7b/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-20190125232054-d66bd3c5d5a6/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= @@ -1893,7 +1869,6 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn 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-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1951,6 +1926,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1981,6 +1957,7 @@ google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/ google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= @@ -1999,8 +1976,9 @@ google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= -google.golang.org/api v0.59.0 h1:fPfFO7gttlXYo2ALuD3HxJzh8vaF++4youI0BkFL6GE= google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0 h1:TXXKS1slM3b2bZNJwD5DV/Tp6/M2cLzLOLh9PjDhrw8= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2046,6 +2024,7 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -2083,9 +2062,12 @@ google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211016002631-37fc39342514/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211018162055-cf77aa76bad2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a h1:8maMHMQp9NroHXhc3HelFX9Ay2lWlXLcdH5mw5Biz0s= google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12 h1:DN5b3HU13J4sMd/QjDx34U6afpaexKTDdop+26pdjdk= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= @@ -2121,6 +2103,7 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= @@ -2210,132 +2193,65 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 istio.io/gogo-genproto v0.0.0-20210113155706-4daf5697332f/go.mod h1:6BwTZRNbWS570wHX/uR1Wqk5e0157TofTAUMzT7N4+s= istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67 h1:vkYEm5mvjuGBxhXSAkFUxVMbcItNu8Wf/jWpJ27b0hQ= istio.io/gogo-genproto v0.0.0-20211115195057-0e34bdd2be67/go.mod h1:6BwTZRNbWS570wHX/uR1Wqk5e0157TofTAUMzT7N4+s= -k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= -k8s.io/api v0.18.4/go.mod h1:lOIQAKYgai1+vz9J7YcDZwC26Z0zQewYOGWdyIPUUQ4= -k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= -k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= -k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= -k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= -k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apiextensions-apiserver v0.18.4/go.mod h1:NYeyeYq4SIpFlPxSAB6jHPIdvu3hL0pc36wuRChybio= -k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= -k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c= k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4= k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.18.4/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= -k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= -k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= -k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= -k8s.io/apiserver v0.18.4/go.mod h1:q+zoFct5ABNnYkGIaGQ3bcbUNdmPyOCoEBcg51LChY8= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= -k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400= k8s.io/apiserver v0.22.2 h1:TdIfZJc6YNhu2WxeAOWq1TvukHF0Sfx0+ln4XK9qnL4= k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= -k8s.io/cli-runtime v0.22.1/go.mod h1:YqwGrlXeEk15Yn3em2xzr435UGwbrCw5x+COQoTYfoo= k8s.io/cli-runtime v0.22.2 h1:fsd9rFk9FSaVq4SUq1fM27c8CFGsYZUJ/3BkgmjYWuY= k8s.io/cli-runtime v0.22.2/go.mod h1:tkm2YeORFpbgQHEK/igqttvPTRIHFRz5kATlw53zlMI= -k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/client-go v0.18.4/go.mod h1:f5sXwL4yAZRkAtzOxRWUhA/N8XzGCb+nPZI8PfobZ9g= -k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= -k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= -k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= -k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= -k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= -k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/code-generator v0.18.4/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.22.0/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= -k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= -k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= -k8s.io/component-base v0.18.4/go.mod h1:7jr/Ef5PGmKwQhyAz/pjByxJbC58mhKAhiaDu0vXfPk= -k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= -k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= -k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= -k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= -k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo= +k8s.io/code-generator v0.22.5/go.mod h1:sbdWCOVob+KaQ5O7xs8PNNaCTpbWVqNgA6EPwLOmRNk= k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M= k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= -k8s.io/component-helpers v0.22.1/go.mod h1:QvBcDbX+qU5I2tMZABBF5fRwAlQwiv771IGBHK9WYh4= k8s.io/component-helpers v0.22.2/go.mod h1:+N61JAR9aKYSWbnLA88YcFr9K/6ISYvRNybX7QW7Rs8= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201203183100-97869a43a9d9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/klog/v2 v2.10.0 h1:R2HDMDJsHVTHA2n4RjwbeYXdOcBymXdX/JRb1v0VGhE= k8s.io/klog/v2 v2.10.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b h1:RQzI0hL8LPCNd9eAZvuG8orAUrxXFiVqBKSU8fs6ygc= k8s.io/kube-openapi v0.0.0-20211020163157-7327e2aaee2b/go.mod h1:gULf0pSS32YtLlO7+li/EV8/0y5mG/sO32H4OUsHIQg= -k8s.io/kubectl v0.22.1/go.mod h1:mjAOgEbMNMtZWxnfM6jd+nPjPsaoLqO5xanc78WcSbw= k8s.io/kubectl v0.22.2 h1:KMyYNZoBshaL3XKx04X07DtpoD4vMrdkfiN/G2Qx/PU= k8s.io/kubectl v0.22.2/go.mod h1:BApg2j0edxLArCOfO0ievI27EeTQqBDMNU9VQH734iQ= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/metrics v0.22.1/go.mod h1:i/ZNap89UkV1gLa26dn7fhKAdheJaKy+moOqJbiif7E= k8s.io/metrics v0.22.2/go.mod h1:GUcsBtpsqQD1tKFS/2wCKu4ZBowwRncLOJH1rgWs3uw= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4= k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +knative.dev/hack v0.0.0-20220224013837-e1785985d364/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI= +knative.dev/networking v0.0.0-20220302134042-e8b2eb995165 h1:mkUDPTqfRPNhsUTVOH53IOx0Utzlfwl48t8lLc1bfL4= +knative.dev/networking v0.0.0-20220302134042-e8b2eb995165/go.mod h1:EdQTSLl8BDeLLrC8pymGOiPMRAknFg+7oRO6MMUts94= +knative.dev/pkg v0.0.0-20220228195509-fe264173447b/go.mod h1:SsH9J6Gz+CvrHmoL0TELJXmMmohqKSQ5bpJvCv+1+ZI= +knative.dev/pkg v0.0.0-20220301181942-2fdd5f232e77 h1:eIH936a0/1X/XQOMN9+O3fw9spGvOJiMVKsBuu8J47U= +knative.dev/pkg v0.0.0-20220301181942-2fdd5f232e77/go.mod h1:SsH9J6Gz+CvrHmoL0TELJXmMmohqKSQ5bpJvCv+1+ZI= oras.land/oras-go v0.4.0 h1:u6+7D+raZDYHwlz/uOwNANiRmyYDSSMW7A9E1xXycUQ= oras.land/oras-go v0.4.0/go.mod h1:VJcU+VE4rkclUbum5C0O7deEZbBYnsnpbGSACwTjOcg= +pgregory.net/rapid v0.3.3/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gEORz0efEja7A= sigs.k8s.io/controller-runtime v0.9.6/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA= @@ -2354,11 +2270,8 @@ sigs.k8s.io/kustomize/kyaml v0.11.0 h1:9KhiCPKaVyuPcgOLJXkvytOvjMJLoxpjodiycb4gH sigs.k8s.io/kustomize/kyaml v0.11.0/go.mod h1:GNMwjim4Ypgp/MueD3zXHLRJEjz7RvtPae0AwlvEMFM= sigs.k8s.io/mcs-api v0.1.0 h1:edDbg0oRGfXw8TmZjKYep06LcJLv/qcYLidejnUp0PM= sigs.k8s.io/mcs-api v0.1.0/go.mod h1:gGiAryeFNB4GBsq2LBmVqSgKoobLxt+p7ii/WG5QYYw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= diff --git a/helm/core/templates/controller-clusterrole.yaml b/helm/core/templates/controller-clusterrole.yaml index d24cd822f..e67baa672 100644 --- a/helm/core/templates/controller-clusterrole.yaml +++ b/helm/core/templates/controller-clusterrole.yaml @@ -117,3 +117,10 @@ rules: - apiGroups: ["config.istio.io", "security.istio.io", "networking.istio.io", "authentication.istio.io", "rbac.istio.io", "telemetry.istio.io", "extensions.istio.io"] verbs: ["get", "watch", "list"] resources: ["*"] + # knative KIngress configuration + - apiGroups: ["networking.internal.knative.dev"] + verbs: ["get","list","watch"] + resources: ["ingresses"] + - apiGroups: ["networking.internal.knative.dev"] + resources: ["ingresses/status"] + verbs: ["get","patch","update"] \ No newline at end of file diff --git a/pkg/bootstrap/server.go b/pkg/bootstrap/server.go index 9d33a284e..e5d7228ec 100644 --- a/pkg/bootstrap/server.go +++ b/pkg/bootstrap/server.go @@ -20,6 +20,10 @@ import ( "net/http" "time" + "github.com/alibaba/higress/pkg/ingress/kube/common" + "github.com/alibaba/higress/pkg/ingress/mcp" + "github.com/alibaba/higress/pkg/ingress/translation" + higresskube "github.com/alibaba/higress/pkg/kube" prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "google.golang.org/grpc" "google.golang.org/grpc/reflection" @@ -46,11 +50,6 @@ import ( "istio.io/pkg/log" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" - - ingressconfig "github.com/alibaba/higress/pkg/ingress/config" - "github.com/alibaba/higress/pkg/ingress/kube/common" - "github.com/alibaba/higress/pkg/ingress/mcp" - higresskube "github.com/alibaba/higress/pkg/kube" ) type XdsOptions struct { @@ -225,9 +224,12 @@ func (s *Server) initConfigController() error { if options.ClusterId == "Kubernetes" { options.ClusterId = "" } - ingressConfig := ingressconfig.NewIngressConfig(s.kubeClient, s.xdsServer, ns, options.ClusterId) - ingressController := ingressConfig.AddLocalCluster(options) + + ingressConfig := translation.NewIngressTranslation(s.kubeClient, s.xdsServer, ns, options.ClusterId) + ingressController, kingressController := ingressConfig.AddLocalCluster(options) + s.configStores = append(s.configStores, ingressConfig) + // Wrap the config controller with a cache. aggregateConfigController, err := configaggregate.MakeCache(s.configStores) if err != nil { @@ -242,7 +244,7 @@ func (s *Server) initConfigController() error { // Defer starting the controller until after the service is created. s.server.RunComponent(func(stop <-chan struct{}) error { - if err := ingressConfig.InitializeCluster(ingressController, stop); err != nil { + if err := ingressConfig.InitializeCluster(ingressController, kingressController, stop); err != nil { return err } go s.configController.Run(stop) diff --git a/pkg/config/constants/constants.go b/pkg/config/constants/constants.go index aee010c5a..74e0656c1 100644 --- a/pkg/config/constants/constants.go +++ b/pkg/config/constants/constants.go @@ -15,3 +15,7 @@ package constants const DefaultIngressClass = "higress" + +const KnativeIngressCRDName = "ingresses.networking.internal.knative.dev" + +const KnativeServicesCRDName = "services.serving.knative.dev" diff --git a/pkg/ingress/config/kingress_config.go b/pkg/ingress/config/kingress_config.go new file mode 100644 index 000000000..064dd5767 --- /dev/null +++ b/pkg/ingress/config/kingress_config.go @@ -0,0 +1,552 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// 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 config + +import ( + "sync" + + networking "istio.io/api/networking/v1alpha3" + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pilot/pkg/util/sets" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/constants" + "istio.io/istio/pkg/config/schema/collection" + "istio.io/istio/pkg/config/schema/gvk" + listersv1 "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" + + "github.com/alibaba/higress/pkg/ingress/kube/annotations" + "github.com/alibaba/higress/pkg/ingress/kube/common" + "github.com/alibaba/higress/pkg/ingress/kube/kingress" + "github.com/alibaba/higress/pkg/ingress/kube/secret" + "github.com/alibaba/higress/pkg/ingress/kube/util" + . "github.com/alibaba/higress/pkg/ingress/log" + "github.com/alibaba/higress/pkg/kube" + "github.com/alibaba/higress/registry/reconcile" +) + +var ( + _ model.ConfigStoreCache = &KIngressConfig{} + _ model.IngressStore = &KIngressConfig{} +) + +type KIngressConfig struct { + // key: cluster id + remoteIngressControllers map[string]common.KIngressController + mutex sync.RWMutex + + ingressRouteCache model.IngressRouteCollection + ingressDomainCache model.IngressDomainCollection + + localKubeClient kube.Client + virtualServiceHandlers []model.EventHandler + gatewayHandlers []model.EventHandler + envoyFilterHandlers []model.EventHandler + WatchErrorHandler cache.WatchErrorHandler + + cachedEnvoyFilters []config.Config + + watchedSecretSet sets.Set + + RegistryReconciler *reconcile.Reconciler + + XDSUpdater model.XDSUpdater + + annotationHandler annotations.AnnotationHandler + + globalGatewayName string + + namespace string + + clusterId string +} + +func NewKIngressConfig(localKubeClient kube.Client, XDSUpdater model.XDSUpdater, namespace, clusterId string) *KIngressConfig { + if localKubeClient.KIngressInformer() == nil { + return nil + } + if clusterId == "Kubernetes" { + clusterId = "" + } + config := &KIngressConfig{ + remoteIngressControllers: make(map[string]common.KIngressController), + localKubeClient: localKubeClient, + XDSUpdater: XDSUpdater, + annotationHandler: annotations.NewAnnotationHandlerManager(), + clusterId: clusterId, + globalGatewayName: namespace + "/" + + common.CreateConvertedName(clusterId, "global"), + watchedSecretSet: sets.NewSet(), + namespace: namespace, + } + + return config +} + +func (m *KIngressConfig) RegisterEventHandler(kind config.GroupVersionKind, f model.EventHandler) { + IngressLog.Infof("register resource %v", kind) + switch kind { + case gvk.VirtualService: + m.virtualServiceHandlers = append(m.virtualServiceHandlers, f) + + case gvk.Gateway: + m.gatewayHandlers = append(m.gatewayHandlers, f) + + case gvk.EnvoyFilter: + m.envoyFilterHandlers = append(m.envoyFilterHandlers, f) + } + + for _, remoteIngressController := range m.remoteIngressControllers { + remoteIngressController.RegisterEventHandler(kind, f) + } +} + +func (m *KIngressConfig) AddLocalCluster(options common.Options) common.KIngressController { + secretController := secret.NewController(m.localKubeClient, options.ClusterId) + secretController.AddEventHandler(m.ReflectSecretChanges) + + var ingressController common.KIngressController + + ingressController = kingress.NewController(m.localKubeClient, m.localKubeClient, options, secretController) + + m.remoteIngressControllers[options.ClusterId] = ingressController + return ingressController +} + +func (m *KIngressConfig) InitializeCluster(ingressController common.KIngressController, stop <-chan struct{}) error { + _ = ingressController.SetWatchErrorHandler(m.WatchErrorHandler) + go ingressController.Run(stop) + return nil +} + +func (m *KIngressConfig) List(typ config.GroupVersionKind, namespace string) ([]config.Config, error) { + if typ == gvk.EnvoyFilter || typ == gvk.DestinationRule || typ == gvk.WasmPlugin || typ == gvk.ServiceEntry { + return nil, nil + } + if typ != gvk.Gateway && typ != gvk.VirtualService { + return nil, common.ErrUnsupportedOp + } + + // Currently, only support list all namespaces gateways or virtualservices. + if namespace != "" { + IngressLog.Warnf("ingress store only support type %s of all namespace.", typ) + return nil, common.ErrUnsupportedOp + } + + var configs []config.Config + m.mutex.RLock() + for _, ingressController := range m.remoteIngressControllers { + configs = append(configs, ingressController.List()...) + } + m.mutex.RUnlock() + + common.SortIngressByCreationTime(configs) + wrapperConfigs := m.createWrapperConfigs(configs) + + IngressLog.Infof("resource type %s, configs number %d", typ, len(wrapperConfigs)) + switch typ { + case gvk.Gateway: + return m.convertGateways(wrapperConfigs), nil + case gvk.VirtualService: + return m.convertVirtualService(wrapperConfigs), nil + } + return nil, nil +} + +func (m *KIngressConfig) createWrapperConfigs(configs []config.Config) []common.WrapperConfig { + var wrapperConfigs []common.WrapperConfig + + // Init global context + clusterSecretListers := map[string]listersv1.SecretLister{} + clusterServiceListers := map[string]listersv1.ServiceLister{} + m.mutex.RLock() + for clusterId, controller := range m.remoteIngressControllers { + clusterSecretListers[clusterId] = controller.SecretLister() + clusterServiceListers[clusterId] = controller.ServiceLister() + } + m.mutex.RUnlock() + globalContext := &annotations.GlobalContext{ + WatchedSecrets: sets.NewSet(), + ClusterSecretLister: clusterSecretListers, + ClusterServiceList: clusterServiceListers, + } + + for idx := range configs { + rawConfig := configs[idx] + annotationsConfig := &annotations.Ingress{ + Meta: annotations.Meta{ + Namespace: rawConfig.Namespace, + Name: rawConfig.Name, + RawClusterId: common.GetRawClusterId(rawConfig.Annotations), + ClusterId: common.GetClusterId(rawConfig.Annotations), + }, + } + _ = m.annotationHandler.Parse(rawConfig.Annotations, annotationsConfig, globalContext) + wrapperConfigs = append(wrapperConfigs, common.WrapperConfig{ + Config: &rawConfig, + AnnotationsConfig: annotationsConfig, + }) + } + + m.mutex.Lock() + m.watchedSecretSet = globalContext.WatchedSecrets + m.mutex.Unlock() + + return wrapperConfigs +} + +func (m *KIngressConfig) convertGateways(configs []common.WrapperConfig) []config.Config { + convertOptions := common.ConvertOptions{ + IngressDomainCache: common.NewIngressDomainCache(), + Gateways: map[string]*common.WrapperGateway{}, + } + + for idx := range configs { + cfg := configs[idx] + clusterId := common.GetClusterId(cfg.Config.Annotations) + m.mutex.RLock() + ingressController := m.remoteIngressControllers[clusterId] + m.mutex.RUnlock() + if ingressController == nil { + continue + } + if err := ingressController.ConvertGateway(&convertOptions, &cfg); err != nil { + IngressLog.Errorf("Convert ingress %s/%s to gateway fail in cluster %s, err %v", cfg.Config.Namespace, cfg.Config.Name, clusterId, err) + } + } + + // apply annotation + for _, wrapperGateway := range convertOptions.Gateways { + m.annotationHandler.ApplyGateway(wrapperGateway.Gateway, wrapperGateway.WrapperConfig.AnnotationsConfig) + } + + m.mutex.Lock() + m.ingressDomainCache = convertOptions.IngressDomainCache.Extract() + m.mutex.Unlock() + out := make([]config.Config, 0, len(convertOptions.Gateways)) + for _, gateway := range convertOptions.Gateways { + cleanHost := common.CleanHost(gateway.Host) + out = append(out, config.Config{ + Meta: config.Meta{ + GroupVersionKind: gvk.Gateway, + Name: common.CreateConvertedName(constants.IstioIngressGatewayName, cleanHost), + Namespace: m.namespace, + Annotations: map[string]string{ + common.ClusterIdAnnotation: gateway.ClusterId, + common.HostAnnotation: gateway.Host, + }, + }, + Spec: gateway.Gateway, + }) + } + return out +} + +func (m *KIngressConfig) convertVirtualService(configs []common.WrapperConfig) []config.Config { + convertOptions := common.ConvertOptions{ + IngressRouteCache: common.NewIngressRouteCache(), + VirtualServices: map[string]*common.WrapperVirtualService{}, + HTTPRoutes: map[string][]*common.WrapperHTTPRoute{}, + Route2Ingress: map[string]*common.WrapperConfigWithRuleKey{}, + } + + // convert http route + for idx := range configs { + cfg := configs[idx] + clusterId := common.GetClusterId(cfg.Config.Annotations) + m.mutex.RLock() + ingressController := m.remoteIngressControllers[clusterId] + m.mutex.RUnlock() + if ingressController == nil { + continue + } + if err := ingressController.ConvertHTTPRoute(&convertOptions, &cfg); err != nil { + IngressLog.Errorf("Convert ingress %s/%s to HTTP route fail in cluster %s, err %v", cfg.Config.Namespace, cfg.Config.Name, clusterId, err) + } + } + + // Apply annotation on routes + for _, routes := range convertOptions.HTTPRoutes { + for _, route := range routes { + m.annotationHandler.ApplyRoute(route.HTTPRoute, route.WrapperConfig.AnnotationsConfig) + } + } + + // Normalize weighted cluster to make sure the sum of weight is 100. + for _, host := range convertOptions.HTTPRoutes { + for _, route := range host { + normalizeWeightedKCluster(convertOptions.IngressRouteCache, route) + } + } + + // Apply annotation on virtual services Only IP-control and do nothing + for _, virtualService := range convertOptions.VirtualServices { + m.annotationHandler.ApplyVirtualServiceHandler(virtualService.VirtualService, virtualService.WrapperConfig.AnnotationsConfig) + } + + // Apply app root for per host. + m.applyAppRoot(&convertOptions) + + // Apply internal active redirect for error page. + m.applyInternalActiveRedirect(&convertOptions) + + m.mutex.Lock() + m.ingressRouteCache = convertOptions.IngressRouteCache.Extract() + m.mutex.Unlock() + + // Convert http route to virtual service + out := make([]config.Config, 0, len(convertOptions.HTTPRoutes)) + for host, routes := range convertOptions.HTTPRoutes { + if len(routes) == 0 { + continue + } + + cleanHost := common.CleanHost(host) + // namespace/name, name format: (istio cluster id)-host + gateways := []string{m.namespace + "/" + + common.CreateConvertedName(m.clusterId, cleanHost), + common.CreateConvertedName(constants.IstioIngressGatewayName, cleanHost)} + if host != "*" { + gateways = append(gateways, m.globalGatewayName) + } + + wrapperVS, exist := convertOptions.VirtualServices[host] + if !exist { + IngressLog.Warnf("virtual service for host %s does not exist.", host) + } + vs := wrapperVS.VirtualService + vs.Gateways = gateways + + for _, route := range routes { + vs.Http = append(vs.Http, route.HTTPRoute) + } + + firstRoute := routes[0] + out = append(out, config.Config{ + Meta: config.Meta{ + GroupVersionKind: gvk.VirtualService, + Name: common.CreateConvertedName(constants.IstioIngressGatewayName, firstRoute.WrapperConfig.Config.Namespace, firstRoute.WrapperConfig.Config.Name, cleanHost), + Namespace: m.namespace, + Annotations: map[string]string{ + common.ClusterIdAnnotation: firstRoute.ClusterId, + }, + }, + Spec: vs, + }) + } + + return out +} + +// Make sure that the sum of traffic split ratio is 100, if it is not 100, it will be normalized +func normalizeWeightedKCluster(cache *common.IngressRouteCache, route *common.WrapperHTTPRoute) { + if len(route.HTTPRoute.Route) == 1 { + route.HTTPRoute.Route[0].Weight = 100 + return + } + + var weightTotal int32 = 0 + for _, routeDestination := range route.HTTPRoute.Route { + weightTotal += routeDestination.Weight + } + var sum int32 + for idx, routeDestination := range route.HTTPRoute.Route { + if idx == 0 { + continue + } + weight := float32(routeDestination.Weight) / float32(weightTotal) + routeDestination.Weight = int32(weight * 100) + sum += routeDestination.Weight + } + route.HTTPRoute.Route[0].Weight = 100 - sum + // Update the recorded status in ingress builder + if cache != nil { + cache.Update(route) + } +} + +func (m *KIngressConfig) applyAppRoot(convertOptions *common.ConvertOptions) { + for host, wrapVS := range convertOptions.VirtualServices { + if wrapVS.AppRoot != "" { + route := &common.WrapperHTTPRoute{ + HTTPRoute: &networking.HTTPRoute{ + Name: common.CreateConvertedName(host, "app-root"), + Match: []*networking.HTTPMatchRequest{ + { + Uri: &networking.StringMatch{ + MatchType: &networking.StringMatch_Exact{ + Exact: "/", + }, + }, + }, + }, + Redirect: &networking.HTTPRedirect{ + RedirectCode: 302, + Uri: wrapVS.AppRoot, + }, + }, + WrapperConfig: wrapVS.WrapperConfig, + ClusterId: wrapVS.WrapperConfig.AnnotationsConfig.ClusterId, + } + convertOptions.HTTPRoutes[host] = append([]*common.WrapperHTTPRoute{route}, convertOptions.HTTPRoutes[host]...) + } + } +} + +func (m *KIngressConfig) applyInternalActiveRedirect(convertOptions *common.ConvertOptions) { + for host, routes := range convertOptions.HTTPRoutes { + var tempRoutes []*common.WrapperHTTPRoute + for _, route := range routes { + tempRoutes = append(tempRoutes, route) + if route.HTTPRoute.InternalActiveRedirect != nil { + fallbackConfig := route.WrapperConfig.AnnotationsConfig.Fallback + if fallbackConfig == nil { + continue + } + + typedNamespace := fallbackConfig.DefaultBackend + internalRedirectRoute := route.HTTPRoute.DeepCopy() + internalRedirectRoute.Name = internalRedirectRoute.Name + annotations.FallbackRouteNameSuffix + internalRedirectRoute.InternalActiveRedirect = nil + internalRedirectRoute.Match = []*networking.HTTPMatchRequest{ + { + Uri: &networking.StringMatch{ + MatchType: &networking.StringMatch_Exact{ + Exact: "/", + }, + }, + Headers: map[string]*networking.StringMatch{ + annotations.FallbackInjectHeaderRouteName: { + MatchType: &networking.StringMatch_Exact{ + Exact: internalRedirectRoute.Name, + }, + }, + annotations.FallbackInjectFallbackService: { + MatchType: &networking.StringMatch_Exact{ + Exact: typedNamespace.String(), + }, + }, + }, + }, + } + internalRedirectRoute.Route = []*networking.HTTPRouteDestination{ + { + Destination: &networking.Destination{ + Host: util.CreateServiceFQDN(typedNamespace.Namespace, typedNamespace.Name), + Port: &networking.PortSelector{ + Number: fallbackConfig.Port, + }, + }, + Weight: 100, + }, + } + + tempRoutes = append([]*common.WrapperHTTPRoute{{ + HTTPRoute: internalRedirectRoute, + WrapperConfig: route.WrapperConfig, + ClusterId: route.ClusterId, + }}, tempRoutes...) + } + } + convertOptions.HTTPRoutes[host] = tempRoutes + } +} + +func (m *KIngressConfig) ReflectSecretChanges(clusterNamespacedName util.ClusterNamespacedName) { + var hit bool + m.mutex.RLock() + if m.watchedSecretSet.Contains(clusterNamespacedName.String()) { + hit = true + } + m.mutex.RUnlock() + + if hit { + push := func(kind config.GroupVersionKind) { + m.XDSUpdater.ConfigUpdate(&model.PushRequest{ + Full: true, + ConfigsUpdated: map[model.ConfigKey]struct{}{{ + Kind: kind, + Name: clusterNamespacedName.Name, + Namespace: clusterNamespacedName.Namespace, + }: {}}, + Reason: []model.TriggerReason{"auth-secret-change"}, + }) + } + push(gvk.VirtualService) + push(gvk.EnvoyFilter) + } +} + +func (m *KIngressConfig) Run(stop <-chan struct{}) {} + +func (m *KIngressConfig) HasSynced() bool { + IngressLog.Info("In Kingress Synced.") + m.mutex.RLock() + defer m.mutex.RUnlock() + + for _, remoteIngressController := range m.remoteIngressControllers { + IngressLog.Info("In Kingress Synced.", remoteIngressController) + if !remoteIngressController.HasSynced() { + return false + } + } + IngressLog.Info("Ingress config controller synced.") + return true +} + +func (m *KIngressConfig) SetWatchErrorHandler(f func(r *cache.Reflector, err error)) error { + m.WatchErrorHandler = f + return nil +} + +func (m *KIngressConfig) GetIngressRoutes() model.IngressRouteCollection { + m.mutex.RLock() + defer m.mutex.RUnlock() + return m.ingressRouteCache +} + +func (m *KIngressConfig) GetIngressDomains() model.IngressDomainCollection { + m.mutex.RLock() + defer m.mutex.RUnlock() + return m.ingressDomainCache +} + +func (m *KIngressConfig) Schemas() collection.Schemas { + return common.IngressIR +} + +func (m *KIngressConfig) Get(config.GroupVersionKind, string, string) *config.Config { + return nil +} + +func (m *KIngressConfig) Create(config.Config) (revision string, err error) { + return "", common.ErrUnsupportedOp +} + +func (m *KIngressConfig) Update(config.Config) (newRevision string, err error) { + return "", common.ErrUnsupportedOp +} + +func (m *KIngressConfig) UpdateStatus(config.Config) (newRevision string, err error) { + return "", common.ErrUnsupportedOp +} + +func (m *KIngressConfig) Patch(config.Config, config.PatchFunc) (string, error) { + return "", common.ErrUnsupportedOp +} + +func (m *KIngressConfig) Delete(config.GroupVersionKind, string, string, *string) error { + return common.ErrUnsupportedOp +} diff --git a/pkg/ingress/config/kingress_config_test.go b/pkg/ingress/config/kingress_config_test.go new file mode 100644 index 000000000..ea96a1ddf --- /dev/null +++ b/pkg/ingress/config/kingress_config_test.go @@ -0,0 +1,481 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// 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 config + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + networking "istio.io/api/networking/v1alpha3" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/schema/gvk" + "k8s.io/apimachinery/pkg/util/intstr" + ingress "knative.dev/networking/pkg/apis/networking/v1alpha1" + + "github.com/alibaba/higress/pkg/ingress/kube/annotations" + "github.com/alibaba/higress/pkg/ingress/kube/common" + kcontrollerv1 "github.com/alibaba/higress/pkg/ingress/kube/kingress" + "github.com/alibaba/higress/pkg/kube" +) + +func TestNormalizeKWeightedCluster(t *testing.T) { + validate := func(route *common.WrapperHTTPRoute) int32 { + var total int32 + fmt.Print("----------------------------") + for _, routeDestination := range route.HTTPRoute.Route { + total += routeDestination.Weight + fmt.Print(routeDestination.Weight) + + } + + return total + } + + var testCases []*common.WrapperHTTPRoute + testCases = append(testCases, &common.WrapperHTTPRoute{ + HTTPRoute: &networking.HTTPRoute{ + Route: []*networking.HTTPRouteDestination{ + { + Weight: 100, + }, + }, + }, + }) + testCases = append(testCases, &common.WrapperHTTPRoute{ + HTTPRoute: &networking.HTTPRoute{ + Route: []*networking.HTTPRouteDestination{ + { + Weight: 98, + }, + }, + }, + }) + + testCases = append(testCases, &common.WrapperHTTPRoute{ + HTTPRoute: &networking.HTTPRoute{ + Route: []*networking.HTTPRouteDestination{ + { + Weight: 0, + }, + { + Weight: 48, + }, + { + Weight: 48, + }, + }, + }, + WeightTotal: 100, + }) + + testCases = append(testCases, &common.WrapperHTTPRoute{ + HTTPRoute: &networking.HTTPRoute{ + Route: []*networking.HTTPRouteDestination{ + { + Weight: 0, + }, + { + Weight: 48, + }, + { + Weight: 48, + }, + }, + }, + WeightTotal: 80, + }) + + for _, route := range testCases { + t.Run("", func(t *testing.T) { + normalizeWeightedKCluster(nil, route) + if validate(route) != 100 { + t.Fatalf("Weight sum should be 100, but actual is %d", validate(route)) + } + }) + } +} + +func TestConvertGatewaysForKIngress(t *testing.T) { + fake := kube.NewFakeClient() + v1Options := common.Options{ + Enable: true, + ClusterId: "kingress", + RawClusterId: "kingress__", + } + kingressV1Controller := kcontrollerv1.NewController(fake, fake, v1Options, nil) + m := NewKIngressConfig(fake, nil, "wakanda", "gw-123-istio") + m.remoteIngressControllers = map[string]common.KIngressController{ + "kingress": kingressV1Controller, + } + + testCases := []struct { + name string + inputConfig []common.WrapperConfig + expect map[string]config.Config + }{ + { + name: "kingress", + inputConfig: []common.WrapperConfig{ + { + Config: &config.Config{ + Meta: config.Meta{ + Name: "test-1", + Namespace: "wakanda", + Annotations: map[string]string{ + common.ClusterIdAnnotation: "kingress", + }, + }, + Spec: ingress.IngressSpec{ + HTTPOption: ingress.HTTPOptionEnabled, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"test.com"}, + SecretName: "test-com", + }, + }, + Rules: []ingress.IngressRule{ + { + Hosts: []string{"foo.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + { + Hosts: []string{"test.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + }, + }, + AnnotationsConfig: &annotations.Ingress{}, + }, + { + Config: &config.Config{ + Meta: config.Meta{ + Name: "test-2", + Namespace: "wakanda", + Annotations: map[string]string{ + common.ClusterIdAnnotation: "kingress", + }, + }, + Spec: ingress.IngressSpec{ + HTTPOption: ingress.HTTPOptionRedirected, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"foo.com"}, + SecretName: "foo-com", + }, + { + Hosts: []string{"test.com"}, + SecretName: "test-com-2", + }, + }, + Rules: []ingress.IngressRule{ + { + Hosts: []string{"foo.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + { + Hosts: []string{"bar.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + { + Hosts: []string{"test.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + }, + }, + AnnotationsConfig: &annotations.Ingress{}, + }, + { + Config: &config.Config{ + Meta: config.Meta{ + Name: "test-3", + Namespace: "wakanda", + Annotations: map[string]string{ + common.ClusterIdAnnotation: "kingress", + }, + }, + Spec: ingress.IngressSpec{ + HTTPOption: ingress.HTTPOptionEnabled, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"foo.com"}, + SecretName: "foo-com", + }, + { + Hosts: []string{"test.com"}, + SecretName: "test-com-3", + }, + }, + Rules: []ingress.IngressRule{ + { + Hosts: []string{"foo.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + { + Hosts: []string{"bar.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + { + Hosts: []string{"test.com"}, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{ + { + Path: "/test", + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "wakanda", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }, + }, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + }, + }, + AnnotationsConfig: &annotations.Ingress{}, + }, + }, + expect: map[string]config.Config{ + "foo.com": { + Meta: config.Meta{ + GroupVersionKind: gvk.Gateway, + Name: "istio-autogenerated-k8s-ingress-foo-com", + Namespace: "wakanda", + Annotations: map[string]string{ + common.ClusterIdAnnotation: "kingress", + common.HostAnnotation: "foo.com", + }, + }, + Spec: &networking.Gateway{ + Servers: []*networking.Server{ + { + Port: &networking.Port{ + Number: 80, + Protocol: "HTTP", + Name: "http-80-ingress-kingress-wakanda-test-1-foo-com", + }, + Hosts: []string{"foo.com"}, + //Tls: &networking.ServerTLSSettings{ + // HttpsRedirect: true, + //}, + }, + { + Port: &networking.Port{ + Number: 443, + Protocol: "HTTPS", + Name: "https-443-ingress-kingress-wakanda-test-2-foo-com", + }, + Hosts: []string{"foo.com"}, + Tls: &networking.ServerTLSSettings{ + Mode: networking.ServerTLSSettings_SIMPLE, + CredentialName: "kubernetes-ingress://kingress__/wakanda/foo-com", + //CipherSuites: []string{"ECDHE-RSA-AES128-GCM-SHA256", "AES256-SHA"}, + }, + }, + }, + }, + }, + "test.com": { + Meta: config.Meta{ + GroupVersionKind: gvk.Gateway, + Name: "istio-autogenerated-k8s-ingress-test-com", + Namespace: "wakanda", + Annotations: map[string]string{ + common.ClusterIdAnnotation: "kingress", + common.HostAnnotation: "test.com", + }, + }, + Spec: &networking.Gateway{ + Servers: []*networking.Server{ + { + Port: &networking.Port{ + Number: 80, + Protocol: "HTTP", + Name: "http-80-ingress-kingress-wakanda-test-1-test-com", + }, + Hosts: []string{"test.com"}, + //Tls: &networking.ServerTLSSettings{ + // HttpsRedirect: true, + //}, + }, + { + Port: &networking.Port{ + Number: 443, + Protocol: "HTTPS", + Name: "https-443-ingress-kingress-wakanda-test-1-test-com", + }, + Hosts: []string{"test.com"}, + Tls: &networking.ServerTLSSettings{ + Mode: networking.ServerTLSSettings_SIMPLE, + CredentialName: "kubernetes-ingress://kingress__/wakanda/test-com", + //CipherSuites: []string{"ECDHE-RSA-AES128-GCM-SHA256", "AES256-SHA"}, + }, + }, + }, + }, + }, + "bar.com": { + Meta: config.Meta{ + GroupVersionKind: gvk.Gateway, + Name: "istio-autogenerated-k8s-ingress-bar-com", + Namespace: "wakanda", + Annotations: map[string]string{ + common.ClusterIdAnnotation: "kingress", + common.HostAnnotation: "bar.com", + }, + }, + Spec: &networking.Gateway{ + Servers: []*networking.Server{ + { + Port: &networking.Port{ + Number: 80, + Protocol: "HTTP", + Name: "http-80-ingress-kingress-wakanda-test-2-bar-com", + }, + Hosts: []string{"bar.com"}, + }, + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result := m.convertGateways(testCase.inputConfig) + + target := map[string]config.Config{} + for _, item := range result { + host := common.GetHost(item.Annotations) + fmt.Print(item) + target[host] = item + } + assert.Equal(t, testCase.expect, target) + }) + } +} diff --git a/pkg/ingress/kube/common/controller.go b/pkg/ingress/kube/common/controller.go index 9ada17f74..71751ad74 100644 --- a/pkg/ingress/kube/common/controller.go +++ b/pkg/ingress/kube/common/controller.go @@ -139,3 +139,27 @@ type IngressController interface { // HasSynced returns true after initial cache synchronization is complete HasSynced() bool } + +type KIngressController interface { + // RegisterEventHandler adds a handler to receive config update events for a + // configuration type + RegisterEventHandler(kind config.GroupVersionKind, handler model.EventHandler) + + List() []config.Config + + ServiceLister() listerv1.ServiceLister + + SecretLister() listerv1.SecretLister + + ConvertGateway(convertOptions *ConvertOptions, wrapper *WrapperConfig) error + + ConvertHTTPRoute(convertOptions *ConvertOptions, wrapper *WrapperConfig) error + + // Run until a signal is received + Run(stop <-chan struct{}) + + SetWatchErrorHandler(func(r *cache.Reflector, err error)) error + + // HasSynced returns true after initial cache synchronization is complete + HasSynced() bool +} diff --git a/pkg/ingress/kube/kingress/controller.go b/pkg/ingress/kube/kingress/controller.go new file mode 100644 index 000000000..adf71e7f1 --- /dev/null +++ b/pkg/ingress/kube/kingress/controller.go @@ -0,0 +1,751 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// 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 kingress + +import ( + "fmt" + "github.com/alibaba/higress/pkg/ingress/kube/annotations" + "path" + "reflect" + "sort" + "strings" + "sync" + "time" + + "github.com/alibaba/higress/pkg/kube" + "github.com/hashicorp/go-multierror" + networking "istio.io/api/networking/v1alpha3" + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pilot/pkg/model/credentials" + "istio.io/istio/pilot/pkg/util/sets" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/constants" + "istio.io/istio/pkg/config/protocol" + "istio.io/istio/pkg/config/schema/gvk" + "istio.io/istio/pkg/kube/controllers" + kerrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + kset "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/wait" + listerv1 "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + ingress "knative.dev/networking/pkg/apis/networking/v1alpha1" + networkingv1alpha1 "knative.dev/networking/pkg/client/listers/networking/v1alpha1" + + "github.com/alibaba/higress/pkg/ingress/kube/common" + "github.com/alibaba/higress/pkg/ingress/kube/kingress/resources" + "github.com/alibaba/higress/pkg/ingress/kube/secret" + . "github.com/alibaba/higress/pkg/ingress/log" +) + +var ( + _ common.KIngressController = &controller{} +) + +const ( + // ClassAnnotationKey points to the annotation for the class of this resource. + ClassAnnotationKey = "networking.knative.dev/ingress.class" + IngressClassName = "higress" +) + +type controller struct { + queue workqueue.RateLimitingInterface + virtualServiceHandlers []model.EventHandler + gatewayHandlers []model.EventHandler + envoyFilterHandlers []model.EventHandler + + options common.Options + + mutex sync.RWMutex + // key: namespace/name + ingresses map[string]*ingress.Ingress + + ingressInformer cache.SharedInformer + ingressLister networkingv1alpha1.IngressLister + serviceInformer cache.SharedInformer + serviceLister listerv1.ServiceLister + secretController secret.SecretController + statusSyncer *statusSyncer +} + +// NewController creates a new Kubernetes controller +func NewController(localKubeClient, client kube.Client, options common.Options, + secretController secret.SecretController) common.KIngressController { + q := workqueue.NewRateLimitingQueue(workqueue.DefaultItemBasedRateLimiter()) + + //var namespace string = "default" + ingressInformer := client.KIngressInformer().Networking().V1alpha1().Ingresses() + serviceInformer := client.KubeInformer().Core().V1().Services() + + c := &controller{ + options: options, + queue: q, + ingresses: make(map[string]*ingress.Ingress), + ingressInformer: ingressInformer.Informer(), + ingressLister: ingressInformer.Lister(), + serviceInformer: serviceInformer.Informer(), + serviceLister: serviceInformer.Lister(), + secretController: secretController, + } + + handler := controllers.LatestVersionHandlerFuncs(controllers.EnqueueForSelf(q)) + c.ingressInformer.AddEventHandler(handler) + + if options.EnableStatus { + c.statusSyncer = newStatusSyncer(localKubeClient, client, c, options.SystemNamespace) + } else { + IngressLog.Infof("Disable status update for cluster %s", options.ClusterId) + } + + return c +} + +func (c *controller) ServiceLister() listerv1.ServiceLister { + return c.serviceLister +} + +func (c *controller) SecretLister() listerv1.SecretLister { + return c.secretController.Lister() +} + +func (c *controller) Run(stop <-chan struct{}) { + if c.statusSyncer != nil { + go c.statusSyncer.run(stop) + } + go c.secretController.Run(stop) + + defer utilruntime.HandleCrash() + defer c.queue.ShutDown() + + if !cache.WaitForCacheSync(stop, c.HasSynced) { + IngressLog.Errorf("Failed to sync ingress controller cache for cluster %s", c.options.ClusterId) + return + } + go wait.Until(c.worker, time.Second, stop) + <-stop +} + +func (c *controller) worker() { + for c.processNextWorkItem() { + } +} + +func (c *controller) processNextWorkItem() bool { + key, quit := c.queue.Get() + if quit { + return false + } + defer c.queue.Done(key) + ingressNamespacedName := key.(types.NamespacedName) + if err := c.onEvent(ingressNamespacedName); err != nil { + IngressLog.Errorf("error processing ingress item (%v) (retrying): %v, cluster: %s", key, err, c.options.ClusterId) + c.queue.AddRateLimited(key) + } else { + c.queue.Forget(key) + } + return true +} + +func (c *controller) onEvent(namespacedName types.NamespacedName) error { + event := model.EventUpdate + ing, err := c.ingressLister.Ingresses(namespacedName.Namespace).Get(namespacedName.Name) + ing.Status.InitializeConditions() + if err != nil { + if kerrors.IsNotFound(err) { + event = model.EventDelete + c.mutex.Lock() + ing = c.ingresses[namespacedName.String()] + delete(c.ingresses, namespacedName.String()) + c.mutex.Unlock() + } else { + return err + } + } + + // ingress deleted, and it is not processed before + if ing == nil { + return nil + } + + // we should check need process only when event is not delete, + // if it is delete event, and previously processed, we need to process too. + if event != model.EventDelete { + shouldProcess, err := c.shouldProcessIngressUpdate(ing) + if err != nil { + return err + } + if !shouldProcess { + IngressLog.Infof("no need process, ingress %s", namespacedName) + return nil + } + } + + vsmetadata := config.Meta{ + Name: ing.Name + "-" + "virtualservice", + Namespace: ing.Namespace, + GroupVersionKind: gvk.VirtualService, + // Set this label so that we do not compare configs and just push. + Labels: map[string]string{constants.AlwaysPushLabel: "true"}, + } + efmetadata := config.Meta{ + Name: ing.Name + "-" + "envoyfilter", + Namespace: ing.Namespace, + GroupVersionKind: gvk.EnvoyFilter, + // Set this label so that we do not compare configs and just push. + Labels: map[string]string{constants.AlwaysPushLabel: "true"}, + } + gatewaymetadata := config.Meta{ + Name: ing.Name + "-" + "gateway", + Namespace: ing.Namespace, + GroupVersionKind: gvk.Gateway, + // Set this label so that we do not compare configs and just push. + Labels: map[string]string{constants.AlwaysPushLabel: "true"}, + } + + for _, f := range c.virtualServiceHandlers { + f(config.Config{Meta: vsmetadata}, config.Config{Meta: vsmetadata}, event) + } + + for _, f := range c.envoyFilterHandlers { + f(config.Config{Meta: efmetadata}, config.Config{Meta: efmetadata}, event) + } + + for _, f := range c.gatewayHandlers { + f(config.Config{Meta: gatewaymetadata}, config.Config{Meta: gatewaymetadata}, event) + } + + return nil +} + +func (c *controller) RegisterEventHandler(kind config.GroupVersionKind, f model.EventHandler) { + switch kind { + case gvk.VirtualService: + c.virtualServiceHandlers = append(c.virtualServiceHandlers, f) + case gvk.Gateway: + c.gatewayHandlers = append(c.gatewayHandlers, f) + case gvk.EnvoyFilter: + c.envoyFilterHandlers = append(c.envoyFilterHandlers, f) + } +} + +func (c *controller) SetWatchErrorHandler(handler func(r *cache.Reflector, err error)) error { + var errs error + if err := c.serviceInformer.SetWatchErrorHandler(handler); err != nil { + errs = multierror.Append(errs, err) + } + if err := c.ingressInformer.SetWatchErrorHandler(handler); err != nil { + errs = multierror.Append(errs, err) + } + if err := c.secretController.Informer().SetWatchErrorHandler(handler); err != nil { + errs = multierror.Append(errs, err) + } + return errs +} + +func (c *controller) HasSynced() bool { + return c.ingressInformer.HasSynced() && c.serviceInformer.HasSynced() && c.secretController.HasSynced() +} + +func (c *controller) List() []config.Config { + c.mutex.RLock() + out := make([]config.Config, 0, len(c.ingresses)) + c.mutex.RUnlock() + + for _, raw := range c.ingressInformer.GetStore().List() { + ing, ok := raw.(*ingress.Ingress) + if !ok { + continue + } + + if should, err := c.shouldProcessIngress(ing); !should || err != nil { + continue + } + copiedConfig := ing.DeepCopy() + + outConfig := config.Config{ + Meta: config.Meta{ + Name: copiedConfig.Name, + Namespace: copiedConfig.Namespace, + Annotations: common.CreateOrUpdateAnnotations(copiedConfig.Annotations, c.options), + Labels: copiedConfig.Labels, + CreationTimestamp: copiedConfig.CreationTimestamp.Time, + }, + Spec: copiedConfig.Spec, + } + + out = append(out, outConfig) + } + + common.RecordIngressNumber(c.options.ClusterId, len(out)) + return out +} + +func extractTLSSecretName(host string, tls []ingress.IngressTLS) string { + if len(tls) == 0 { + return "" + } + + for _, t := range tls { + match := false + for _, h := range t.Hosts { + if h == host { + match = true + } + } + + if match { + return t.SecretName + } + } + + return "" +} + +func (c *controller) ConvertGateway(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig) error { + if convertOptions == nil { + return fmt.Errorf("convertOptions is nil") + } + if wrapper == nil { + return fmt.Errorf("wrapperConfig is nil") + } + + cfg := wrapper.Config + kingressv1alpha1, ok := cfg.Spec.(ingress.IngressSpec) + + if !ok { + common.IncrementInvalidIngress(c.options.ClusterId, common.Unknown) + return fmt.Errorf("convert type is invalid in cluster %s", c.options.ClusterId) + } + if len(kingressv1alpha1.Rules) == 0 { + common.IncrementInvalidIngress(c.options.ClusterId, common.EmptyRule) + return fmt.Errorf("invalid ingress rule %s:%s in cluster %s, `rules` must be specified", cfg.Namespace, cfg.Name, c.options.ClusterId) + } + + for _, rule := range kingressv1alpha1.Rules { + for _, ruleHost := range rule.Hosts { + cleanHost := common.CleanHost(ruleHost) + // Need create builder for every rule. + domainBuilder := &common.IngressDomainBuilder{ + ClusterId: c.options.ClusterId, + Protocol: common.HTTP, + Host: ruleHost, + Ingress: cfg, + Event: common.Normal, + } + // Extract the previous gateway and builder + wrapperGateway, exist := convertOptions.Gateways[ruleHost] + preDomainBuilder, _ := convertOptions.IngressDomainCache.Valid[ruleHost] + if !exist { + wrapperGateway = &common.WrapperGateway{ + Gateway: &networking.Gateway{}, + WrapperConfig: wrapper, + ClusterId: c.options.ClusterId, + Host: ruleHost, + } + if c.options.GatewaySelectorKey != "" { + wrapperGateway.Gateway.Selector = map[string]string{c.options.GatewaySelectorKey: c.options.GatewaySelectorValue} + } + if rule.Visibility == ingress.IngressVisibilityClusterLocal { + wrapperGateway.Gateway.Servers = append(wrapperGateway.Gateway.Servers, &networking.Server{ + Port: &networking.Port{ + Number: 8081, + Protocol: string(protocol.HTTP), + Name: common.CreateConvertedName("http-8081-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost), + }, + Hosts: []string{ruleHost}, + }) + + } else { + wrapperGateway.Gateway.Servers = append(wrapperGateway.Gateway.Servers, &networking.Server{ + Port: &networking.Port{ + Number: 80, + Protocol: string(protocol.HTTP), + Name: common.CreateConvertedName("http-80-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost), + }, + Hosts: []string{ruleHost}, + }) + } + + // Add new gateway, builder + convertOptions.Gateways[ruleHost] = wrapperGateway + convertOptions.IngressDomainCache.Valid[ruleHost] = domainBuilder + } else { + // Fallback to get downstream tls from current ingress. + if wrapperGateway.WrapperConfig.AnnotationsConfig.DownstreamTLS == nil { + wrapperGateway.WrapperConfig.AnnotationsConfig.DownstreamTLS = wrapper.AnnotationsConfig.DownstreamTLS + } + } + //Redirect option + if isIngressPublic(&kingressv1alpha1) && (kingressv1alpha1.HTTPOption == ingress.HTTPOptionRedirected) { + for _, server := range wrapperGateway.Gateway.Servers { + if protocol.Parse(server.Port.Protocol).IsHTTP() { + server.Tls = &networking.ServerTLSSettings{ + HttpsRedirect: true, + } + } + } + } else if isIngressPublic(&kingressv1alpha1) && (kingressv1alpha1.HTTPOption == ingress.HTTPOptionEnabled) { + for _, server := range wrapperGateway.Gateway.Servers { + if protocol.Parse(server.Port.Protocol).IsHTTP() { + server.Tls = nil + } + } + } + + // There are no tls settings, so just skip. + if len(kingressv1alpha1.TLS) == 0 { + continue + } + + // Get tls secret matching the rule host + secretName := extractTLSSecretName(ruleHost, kingressv1alpha1.TLS) + if secretName == "" { + // There no matching secret, so just skip. + continue + } + + domainBuilder.Protocol = common.HTTPS + domainBuilder.SecretName = path.Join(c.options.ClusterId, cfg.Namespace, secretName) + + // There is a matching secret and the gateway has already a tls secret. + // We should report the duplicated tls secret event. + if wrapperGateway.IsHTTPS() { + domainBuilder.Event = common.DuplicatedTls + domainBuilder.PreIngress = preDomainBuilder.Ingress + convertOptions.IngressDomainCache.Invalid = append(convertOptions.IngressDomainCache.Invalid, + domainBuilder.Build()) + continue + } + + // Append https server + wrapperGateway.Gateway.Servers = append(wrapperGateway.Gateway.Servers, &networking.Server{ + Port: &networking.Port{ + Number: 443, + Protocol: string(protocol.HTTPS), + Name: common.CreateConvertedName("https-443-ingress", c.options.ClusterId, cfg.Namespace, cfg.Name, cleanHost), + }, + Hosts: []string{ruleHost}, + Tls: &networking.ServerTLSSettings{ + Mode: networking.ServerTLSSettings_SIMPLE, + CredentialName: credentials.ToKubernetesIngressResource(c.options.RawClusterId, cfg.Namespace, secretName), + }, + }) + + // Update domain builder + convertOptions.IngressDomainCache.Valid[ruleHost] = domainBuilder + } + + } + + return nil +} + +func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig) error { + if convertOptions == nil { + return fmt.Errorf("convertOptions is nil") + } + if wrapper == nil { + return fmt.Errorf("wrapperConfig is nil") + } + + cfg := wrapper.Config + KingressV1, ok := cfg.Spec.(ingress.IngressSpec) + if !ok { + common.IncrementInvalidIngress(c.options.ClusterId, common.Unknown) + return fmt.Errorf("convert type is invalid in cluster %s", c.options.ClusterId) + } + if len(KingressV1.Rules) == 0 { + common.IncrementInvalidIngress(c.options.ClusterId, common.EmptyRule) + return fmt.Errorf("invalid ingress rule %s:%s in cluster %s, `rules` must be specified", cfg.Namespace, cfg.Name, c.options.ClusterId) + } + convertOptions.HasDefaultBackend = false + // In one ingress, we will limit the rule conflict. + // When the host, pathType, path of two rule are same, we think there is a conflict event. + definedRules := sets.NewSet() + + var ( + // But in across ingresses case, we will restrict this limit. + // When the {host, path, headers, method, params} of two rule in different ingress are same, we think there is a conflict event. + tempRuleKey []string + ) + + for _, rule := range KingressV1.Rules { + for _, rulehost := range rule.Hosts { + if rule.HTTP == nil || len(rule.HTTP.Paths) == 0 { + IngressLog.Warnf("invalid ingress rule %s:%s for host %q in cluster %s, no paths defined", cfg.Namespace, cfg.Name, rulehost, c.options.ClusterId) + continue + } + wrapperVS, exist := convertOptions.VirtualServices[rulehost] + if !exist { + wrapperVS = &common.WrapperVirtualService{ + VirtualService: &networking.VirtualService{ + Hosts: []string{rulehost}, + }, + WrapperConfig: wrapper, + } + convertOptions.VirtualServices[rulehost] = wrapperVS + } + wrapperHttpRoutes := make([]*common.WrapperHTTPRoute, 0, len(rule.HTTP.Paths)) + for _, httpPath := range rule.HTTP.Paths { + wrapperHttpRoute := &common.WrapperHTTPRoute{ + HTTPRoute: &networking.HTTPRoute{}, + WrapperConfig: wrapper, + Host: rulehost, + ClusterId: c.options.ClusterId, + } + + var pathType common.PathType + originPath := httpPath.Path + pathType = common.Prefix + wrapperHttpRoute.OriginPath = originPath + wrapperHttpRoute.OriginPathType = pathType + wrapperHttpRoute.HTTPRoute = resources.MakeVirtualServiceRoute(transformHosts(rulehost), &httpPath) + wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, wrapperHttpRoute) + ingressRouteBuilder := convertOptions.IngressRouteCache.New(wrapperHttpRoute) + hostAndPath := wrapperHttpRoute.PathFormat() + key := createRuleKey(cfg.Annotations, hostAndPath) + wrapperHttpRoute.RuleKey = key + if WrapPreIngress, exist := convertOptions.Route2Ingress[key]; exist { + ingressRouteBuilder.PreIngress = WrapPreIngress.Config + ingressRouteBuilder.Event = common.DuplicatedRoute + } + tempRuleKey = append(tempRuleKey, key) + + // Two duplicated rules in the same ingress. + if ingressRouteBuilder.Event == common.Normal { + pathFormat := wrapperHttpRoute.PathFormat() + if definedRules.Contains(pathFormat) { + ingressRouteBuilder.PreIngress = cfg + ingressRouteBuilder.Event = common.DuplicatedRoute + } + definedRules.Insert(pathFormat) + } + + // backend service check + var event common.Event + destinationConfig := wrapper.AnnotationsConfig.Destination + event = c.IngressRouteBuilderServicesCheck(&httpPath, cfg.Namespace, ingressRouteBuilder, destinationConfig) + + if destinationConfig != nil { + wrapperHttpRoute.WeightTotal = int32(destinationConfig.WeightSum) + } + + if ingressRouteBuilder.Event != common.Normal { + event = ingressRouteBuilder.Event + } + + if event != common.Normal { + common.IncrementInvalidIngress(c.options.ClusterId, event) + ingressRouteBuilder.Event = event + } else { + wrapperHttpRoutes = append(wrapperHttpRoutes, wrapperHttpRoute) + } + convertOptions.IngressRouteCache.Add(ingressRouteBuilder) + } + + for idx, item := range tempRuleKey { + if val, exist := convertOptions.Route2Ingress[item]; !exist || strings.Compare(val.RuleKey, tempRuleKey[idx]) != 0 { + convertOptions.Route2Ingress[item] = &common.WrapperConfigWithRuleKey{ + Config: cfg, + RuleKey: tempRuleKey[idx], + } + } + } + + old, f := convertOptions.HTTPRoutes[rulehost] + if f { + old = append(old, wrapperHttpRoutes...) + convertOptions.HTTPRoutes[rulehost] = old + } else { + convertOptions.HTTPRoutes[rulehost] = wrapperHttpRoutes + } + + // Sort, exact -> prefix -> regex + routes := convertOptions.HTTPRoutes[rulehost] + IngressLog.Debugf("routes of host %s is %v", rulehost, routes) + common.SortHTTPRoutes(routes) + } + + } + return nil +} +func (c *controller) IngressRouteBuilderServicesCheck(httppath *ingress.HTTPIngressPath, namespace string, + builder *common.IngressRouteBuilder, config *annotations.DestinationConfig) common.Event { + + //backend check + if httppath.Splits == nil { + return common.InvalidBackendService + } + for _, split := range httppath.Splits { + if split.ServiceName == "" { + return common.InvalidBackendService + } + backendService := model.BackendService{ + Namespace: namespace, + Name: split.ServiceName, + Port: uint32(split.ServicePort.IntValue()), + Weight: int32(split.Percent), + } + builder.ServiceList = append(builder.ServiceList, backendService) + } + return common.Normal +} + +func (c *controller) shouldProcessIngressWithClass(ing *ingress.Ingress) bool { + if classValue, found := ing.GetAnnotations()[ClassAnnotationKey]; !found || classValue != IngressClassName { + IngressLog.Debugf("Ingress class %s does not match knative IngressCLassName %s.", classValue, IngressClassName) + return false + } + return true +} + +func (c *controller) shouldProcessIngress(i *ingress.Ingress) (bool, error) { + //check namespace + if c.shouldProcessIngressWithClass(i) { + switch c.options.WatchNamespace { + case "": + return true, nil + default: + return c.options.WatchNamespace == i.Namespace, nil + } + } + return false, nil + +} + +// shouldProcessIngressUpdate checks whether we should renotify registered handlers about an update event +func (c *controller) shouldProcessIngressUpdate(ing *ingress.Ingress) (bool, error) { + shouldProcess, err := c.shouldProcessIngress(ing) + if err != nil { + return false, err + } + + namespacedName := ing.Namespace + "/" + ing.Name + if shouldProcess { + // record processed ingress + c.mutex.Lock() + preConfig, exist := c.ingresses[namespacedName] + c.ingresses[namespacedName] = ing + c.mutex.Unlock() + + // We only care about annotations, labels and spec. + if exist { + if !reflect.DeepEqual(preConfig.Annotations, ing.Annotations) { + IngressLog.Debugf("Annotations of ingress %s changed, should process.", namespacedName) + return true, nil + } + if !reflect.DeepEqual(preConfig.Labels, ing.Labels) { + IngressLog.Debugf("Labels of ingress %s changed, should process.", namespacedName) + return true, nil + } + if !reflect.DeepEqual(preConfig.Spec, ing.Spec) { + IngressLog.Debugf("Spec of ingress %s changed, should process.", namespacedName) + return true, nil + } + + return false, nil + } + IngressLog.Debugf("First receive relative ingress %s, should process.", namespacedName) + return true, nil + } + + c.mutex.Lock() + _, preProcessed := c.ingresses[namespacedName] + // previous processed but should not currently, delete it + if preProcessed && !shouldProcess { + delete(c.ingresses, namespacedName) + } + c.mutex.Unlock() + + return preProcessed, nil +} + +// createRuleKey according to the pathType, path, methods, headers, params of rules +func createRuleKey(annots map[string]string, hostAndPath string) string { + var ( + headers [][2]string + params [][2]string + sb strings.Builder + ) + + sep := "\n\n" + + // path + sb.WriteString(hostAndPath) + sb.WriteString(sep) + + // methods + if str, ok := annots[annotations.HigressAnnotationsPrefix+"/"+annotations.MatchMethod]; ok { + sb.WriteString(str) + } + sb.WriteString(sep) + + start := len(annotations.HigressAnnotationsPrefix) + 1 // example: higress.io/exact-match-header-key: value + // headers && params + for k, val := range annots { + if idx := strings.Index(k, annotations.MatchHeader); idx != -1 { + key := k[start:idx] + k[idx+len(annotations.MatchHeader)+1:] + headers = append(headers, [2]string{key, val}) + } + if idx := strings.Index(k, annotations.MatchQuery); idx != -1 { + key := k[start:idx] + k[idx+len(annotations.MatchQuery)+1:] + params = append(params, [2]string{key, val}) + } + } + sort.SliceStable(headers, func(i, j int) bool { + return headers[i][0] < headers[j][0] + }) + sort.SliceStable(params, func(i, j int) bool { + return params[i][0] < params[j][0] + }) + for idx := range headers { + if idx != 0 { + sb.WriteByte('\n') + } + sb.WriteString(headers[idx][0]) + sb.WriteByte('\t') + sb.WriteString(headers[idx][1]) + } + sb.WriteString(sep) + for idx := range params { + if idx != 0 { + sb.WriteByte('\n') + } + sb.WriteString(params[idx][0]) + sb.WriteByte('\t') + sb.WriteString(params[idx][1]) + } + sb.WriteString(sep) + + return sb.String() +} + +func transformHosts(host string) kset.String { + hosts := []string{host} + out := kset.NewString() + out.Insert(hosts...) + return out +} + +func isIngressPublic(ingSpec *ingress.IngressSpec) bool { + for _, rule := range ingSpec.Rules { + if rule.Visibility == ingress.IngressVisibilityExternalIP { + return true + } + } + return false +} diff --git a/pkg/ingress/kube/kingress/controller_test.go b/pkg/ingress/kube/kingress/controller_test.go new file mode 100644 index 000000000..ac39ce77c --- /dev/null +++ b/pkg/ingress/kube/kingress/controller_test.go @@ -0,0 +1,604 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// 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 kingress + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/require" + istiov1alpha3 "istio.io/api/networking/v1alpha3" + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pkg/config" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "knative.dev/networking/pkg/apis/networking" + "knative.dev/networking/pkg/apis/networking/v1alpha1" + ingress "knative.dev/networking/pkg/apis/networking/v1alpha1" + "knative.dev/pkg/kmeta" + + "github.com/alibaba/higress/pkg/ingress/kube/annotations" + "github.com/alibaba/higress/pkg/ingress/kube/common" + "github.com/alibaba/higress/pkg/ingress/kube/secret" + "github.com/alibaba/higress/pkg/kube" +) + +const ( + testNS = "testNS" + IstioIngressClassNametest = "higress" +) + +var ( + ingressRules = []v1alpha1.IngressRule{{ + Hosts: []string{ + "host-tls.example.com", + }, + HTTP: &v1alpha1.HTTPIngressRuleValue{ + Paths: []v1alpha1.HTTPIngressPath{{ + Splits: []v1alpha1.IngressBackendSplit{{ + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: testNS, + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }}, + }, + Visibility: v1alpha1.IngressVisibilityExternalIP, + }, { + Hosts: []string{ + "host-tls.test-ns.svc.cluster.local", + }, + HTTP: &v1alpha1.HTTPIngressRuleValue{ + Paths: []v1alpha1.HTTPIngressPath{{ + Splits: []v1alpha1.IngressBackendSplit{{ + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: testNS, + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }}, + }, + Visibility: v1alpha1.IngressVisibilityClusterLocal, + }} + + ingressTLS = []v1alpha1.IngressTLS{{ + Hosts: []string{"host-tls.example.com"}, + SecretName: "secret0", + SecretNamespace: "istio-system", + }} + + // The gateway server according to ingressTLS. + ingressTLSServer = &istiov1alpha3.Server{ + Hosts: []string{"host-tls.example.com"}, + Port: &istiov1alpha3.Port{ + Name: "test-ns/reconciling-ingress:0", + Number: 443, + Protocol: "HTTPS", + }, + Tls: &istiov1alpha3.ServerTLSSettings{ + Mode: istiov1alpha3.ServerTLSSettings_SIMPLE, + ServerCertificate: "tls.crt", + PrivateKey: "tls.key", + CredentialName: "secret0", + }, + } + + ingressHTTPServer = &istiov1alpha3.Server{ + Hosts: []string{"host-tls.example.com"}, + Port: &istiov1alpha3.Port{ + Name: "http-server", + Number: 80, + Protocol: "HTTP", + }, + } + + ingressHTTPRedirectServer = &istiov1alpha3.Server{ + Hosts: []string{"*"}, + Port: &istiov1alpha3.Port{ + Name: "http-server", + Number: 80, + Protocol: "HTTP", + }, + Tls: &istiov1alpha3.ServerTLSSettings{ + HttpsRedirect: true, + }, + } + + // The gateway server irrelevant to ingressTLS. + irrelevantServer = &istiov1alpha3.Server{ + Hosts: []string{"host-tls.example.com", "host-tls.test-ns.svc.cluster.local"}, + Port: &istiov1alpha3.Port{ + Name: "test:0", + Number: 443, + Protocol: "HTTPS", + }, + Tls: &istiov1alpha3.ServerTLSSettings{ + Mode: istiov1alpha3.ServerTLSSettings_SIMPLE, + ServerCertificate: "tls.crt", + PrivateKey: "tls.key", + CredentialName: "other-secret", + }, + } + irrelevantServer1 = &istiov1alpha3.Server{ + Hosts: []string{"*"}, + Port: &istiov1alpha3.Port{ + Name: "http-server", + Number: 80, + Protocol: "HTTP", + }, + } + + deletionTime = metav1.NewTime(time.Unix(1e9, 0)) +) + +func TestKIngressControllerConventions(t *testing.T) { + fakeClient := kube.NewFakeClient() + localKubeClient, client := fakeClient, fakeClient + + options := common.Options{IngressClass: "mse", ClusterId: "", EnableStatus: true} + + secretController := secret.NewController(localKubeClient, options.ClusterId) + ingressController := NewController(localKubeClient, client, options, secretController) + + testcases := map[string]func(*testing.T, common.KIngressController){ + "test convert HTTPRoute": testConvertHTTPRoute, + } + for name, tc := range testcases { + t.Run(name, func(t *testing.T) { + tc(t, ingressController) + }) + } +} + +func testConvertHTTPRoute(t *testing.T, c common.KIngressController) { + testcases := []struct { + description string + input struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + } + expectNoError bool + }{ + { + description: "convertOptions is nil", + input: struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + }{ + options: nil, + wrapperConfig: nil, + }, + expectNoError: false, + }, { + description: "convertOptions is not nil but empty", + input: struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + }{ + options: &common.ConvertOptions{}, + wrapperConfig: &common.WrapperConfig{ + Config: &config.Config{}, + AnnotationsConfig: &annotations.Ingress{}, + }, + }, + expectNoError: false, + }, { + description: "valid httpRoute convention,invalid backend", + input: struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + }{ + options: &common.ConvertOptions{ + IngressDomainCache: &common.IngressDomainCache{ + Valid: make(map[string]*common.IngressDomainBuilder), + Invalid: make([]model.IngressDomain, 0), + }, + Route2Ingress: map[string]*common.WrapperConfigWithRuleKey{}, + VirtualServices: make(map[string]*common.WrapperVirtualService), + Gateways: make(map[string]*common.WrapperGateway), + IngressRouteCache: &common.IngressRouteCache{}, + HTTPRoutes: make(map[string][]*common.WrapperHTTPRoute), + }, + wrapperConfig: &common.WrapperConfig{Config: &config.Config{ + Spec: ingress.IngressSpec{Rules: []ingress.IngressRule{ + { + Hosts: []string{ + "host-tls.example.com", + }, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{{ + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{}, + Percent: 100, + }}, + }}, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"test1", "test2"}, + SecretName: "test", + }, + }}, + }, AnnotationsConfig: &annotations.Ingress{}, + }, + }, + expectNoError: true, + }, { + description: "valid httpRoute convention,invalid split", + input: struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + }{ + options: &common.ConvertOptions{ + IngressDomainCache: &common.IngressDomainCache{ + Valid: make(map[string]*common.IngressDomainBuilder), + Invalid: make([]model.IngressDomain, 0), + }, + Route2Ingress: map[string]*common.WrapperConfigWithRuleKey{}, + VirtualServices: make(map[string]*common.WrapperVirtualService), + Gateways: make(map[string]*common.WrapperGateway), + IngressRouteCache: &common.IngressRouteCache{}, + HTTPRoutes: make(map[string][]*common.WrapperHTTPRoute), + }, + wrapperConfig: &common.WrapperConfig{Config: &config.Config{ + Spec: ingress.IngressSpec{Rules: []ingress.IngressRule{ + { + Hosts: []string{ + "host-tls.example.com", + }, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{{ + Splits: []ingress.IngressBackendSplit{{}}, + }}, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"test1", "test2"}, + SecretName: "test", + }, + }}, + }, AnnotationsConfig: &annotations.Ingress{}, + }, + }, + expectNoError: true, + }, + { + description: "valid httpRoute convention, vaild ingress", + input: struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + }{ + options: &common.ConvertOptions{ + IngressDomainCache: &common.IngressDomainCache{ + Valid: make(map[string]*common.IngressDomainBuilder), + Invalid: make([]model.IngressDomain, 0), + }, + Route2Ingress: map[string]*common.WrapperConfigWithRuleKey{}, + VirtualServices: make(map[string]*common.WrapperVirtualService), + Gateways: make(map[string]*common.WrapperGateway), + IngressRouteCache: common.NewIngressRouteCache(), + HTTPRoutes: make(map[string][]*common.WrapperHTTPRoute), + }, + wrapperConfig: &common.WrapperConfig{Config: &config.Config{ + Meta: config.Meta{ + Name: "host-tls-test", + Namespace: testNS, + }, + Spec: ingress.IngressSpec{Rules: []ingress.IngressRule{ + { + Hosts: []string{ + "host-tls.example.com", + }, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{{ + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: testNS, + ServiceName: "v1-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }}, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"test1", "test2"}, + SecretName: "test", + }, + }}, + }, AnnotationsConfig: &annotations.Ingress{}, + }, + }, + expectNoError: true, + }, { + description: "valid httpRoute convention, Spec Rule All open Ingress", + input: struct { + options *common.ConvertOptions + wrapperConfig *common.WrapperConfig + }{ + options: &common.ConvertOptions{ + IngressDomainCache: &common.IngressDomainCache{ + Valid: make(map[string]*common.IngressDomainBuilder), + Invalid: make([]model.IngressDomain, 0), + }, + Route2Ingress: map[string]*common.WrapperConfigWithRuleKey{}, + VirtualServices: make(map[string]*common.WrapperVirtualService), + Gateways: make(map[string]*common.WrapperGateway), + IngressRouteCache: common.NewIngressRouteCache(), + HTTPRoutes: make(map[string][]*common.WrapperHTTPRoute), + }, + wrapperConfig: &common.WrapperConfig{Config: &config.Config{ + Meta: config.Meta{ + Name: "host-kingress-all-open-test", + Namespace: "default", + }, + Spec: ingress.IngressSpec{Rules: []ingress.IngressRule{ + { + Hosts: []string{ + "hello.default", + "hello.default.svc", + "hello.default.svc.cluster.local", + }, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{{ + Path: "/pet/", + Splits: []v1alpha1.IngressBackendSplit{{ + AppendHeaders: map[string]string{ + "Knative-Serving-Namespace": "default", + "Knative-Serving-Revision": "hello-00002", + }, + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "default", + ServiceName: "hello-00002", + ServicePort: intstr.FromInt(80), + }, + Percent: 90, + }, { + AppendHeaders: map[string]string{ + "Knative-Serving-Namespace": "default", + "Knative-Serving-Revision": "hello-00001", + }, + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "default", + ServiceName: "hello-00001", + ServicePort: intstr.FromInt(80), + }, + Percent: 10, + }}, + AppendHeaders: map[string]string{ + "ugh": "blah", + }, + }}, + }, + Visibility: ingress.IngressVisibilityClusterLocal, + }, { + Hosts: []string{ + "hello.default.zwj.com", + }, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{{ + Splits: []v1alpha1.IngressBackendSplit{{ + AppendHeaders: map[string]string{ + "Knative-Serving-Namespace": "default", + "Knative-Serving-Revision": "hello-00002", + }, + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "default", + ServiceName: "hello-00002", + ServicePort: intstr.FromInt(80), + }, + Percent: 90, + }, { + AppendHeaders: map[string]string{ + "Knative-Serving-Namespace": "default", + "Knative-Serving-Revision": "hello-00001", + }, + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "default", + ServiceName: "hello-00001", + ServicePort: intstr.FromInt(80), + }, + Percent: 10, + }}, + }}, + }, + Visibility: ingress.IngressVisibilityExternalIP, + }, + }, + TLS: []ingress.IngressTLS{ + { + Hosts: []string{"test1", "test2"}, + SecretName: "test", + }, + }}, + }, AnnotationsConfig: &annotations.Ingress{}, + }, + }, + expectNoError: true, + }, + } + + for _, testcase := range testcases { + err := c.ConvertHTTPRoute(testcase.input.options, testcase.input.wrapperConfig) + if err != nil { + require.Equal(t, testcase.expectNoError, false) + } else { + require.Equal(t, testcase.expectNoError, true) + } + } +} + +func TestExtractTLSSecretName(t *testing.T) { + testcases := []struct { + input struct { + host string + tls []ingress.IngressTLS + } + expect string + description string + }{ + { + input: struct { + host string + tls []ingress.IngressTLS + }{ + host: "", + tls: nil, + }, + expect: "", + description: "both are nil", + }, + { + input: struct { + host string + tls []ingress.IngressTLS + }{ + host: "test", + tls: []ingress.IngressTLS{ + { + Hosts: []string{"test"}, + SecretName: "test-secret", + }, + { + Hosts: []string{"test1"}, + SecretName: "test1-secret", + }, + }, + }, + expect: "test-secret", + description: "found secret name", + }, + } + + for _, testcase := range testcases { + actual := extractTLSSecretName(testcase.input.host, testcase.input.tls) + require.Equal(t, testcase.expect, actual) + } +} + +func TestShouldProcessIngressUpdate(t *testing.T) { + c := controller{ + options: common.Options{}, + ingresses: make(map[string]*ingress.Ingress), + } + ingress1 := &ingress.Ingress{ + + ObjectMeta: metav1.ObjectMeta{ + Name: "test-1", + }, + Spec: ingress.IngressSpec{ + Rules: []ingress.IngressRule{ + { + Hosts: []string{ + "host-tls.example.com", + }, + HTTP: &ingress.HTTPIngressRuleValue{ + Paths: []ingress.HTTPIngressPath{{ + Splits: []ingress.IngressBackendSplit{{ + IngressBackend: ingress.IngressBackend{ + ServiceNamespace: "testNs", + ServiceName: "test-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + }}, + }, + }, + }, + }, + } + addAnnotations(ingress1, map[string]string{networking.IngressClassAnnotationKey: IstioIngressClassNametest}) + + should, _ := c.shouldProcessIngressUpdate(ingress1) + if !should { + t.Fatal("should be true") + } + + ingress2 := *ingress1 + should, _ = c.shouldProcessIngressUpdate(&ingress2) + if should { + t.Fatal("should be false") + } + + ingress3 := *ingress1 + ingress3.Annotations = map[string]string{ + "test": "true", + } + should, _ = c.shouldProcessIngressUpdate(&ingress3) + if !should { + t.Fatal("should be true") + } + ingress4 := ingress1.DeepCopy() + addAnnotations(ingress4, map[string]string{networking.IngressClassAnnotationKey: "fake-classname"}) + should, _ = c.shouldProcessIngressUpdate(ingress4) + if should { + t.Fatal("should be false") + } + //可能有坑,annotation更新可能会引起ingress资源的反复处理。 + +} + +func addAnnotations(ing *ingress.Ingress, annos map[string]string) *ingress.Ingress { + // UnionMaps(a, b) where value from b wins. Use annos for second arg. + ing.ObjectMeta.Annotations = kmeta.UnionMaps(ing.ObjectMeta.Annotations, annos) + return ing +} + +func TestCreateRuleKey(t *testing.T) { + sep := "\n\n" + wrapperHttpRoute := &common.WrapperHTTPRoute{ + Host: "higress.com", + OriginPathType: common.Prefix, + OriginPath: "/foo", + } + + annots := annotations.Annotations{ + buildHigressAnnotationKey(annotations.MatchMethod): "GET PUT", + buildHigressAnnotationKey("exact-" + annotations.MatchHeader + "-abc"): "123", + buildHigressAnnotationKey("prefix-" + annotations.MatchHeader + "-def"): "456", + buildHigressAnnotationKey("exact-" + annotations.MatchQuery + "-region"): "beijing", + buildHigressAnnotationKey("prefix-" + annotations.MatchQuery + "-user-id"): "user-", + } + expect := "higress.com-prefix-/foo" + sep + //host-pathType-path + "GET PUT" + sep + // method + "exact-abc\t123" + "\n" + "prefix-def\t456" + sep + // header + "exact-region\tbeijing" + "\n" + "prefix-user-id\tuser-" + sep // params + + key := createRuleKey(annots, wrapperHttpRoute.PathFormat()) + if diff := cmp.Diff(expect, key); diff != "" { + + t.Errorf("CreateRuleKey() mismatch (-want +got):\n%s", diff) + } +} + +func buildHigressAnnotationKey(key string) string { + return annotations.HigressAnnotationsPrefix + "/" + key +} diff --git a/pkg/ingress/kube/kingress/resources/doc.go b/pkg/ingress/kube/kingress/resources/doc.go new file mode 100644 index 000000000..b45e92f37 --- /dev/null +++ b/pkg/ingress/kube/kingress/resources/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package resources holds simple functions for synthesizing child resources from +// an Ingress resource and any relevant Ingress controller configuration. +package resources diff --git a/pkg/ingress/kube/kingress/resources/virtual_service.go b/pkg/ingress/kube/kingress/resources/virtual_service.go new file mode 100644 index 000000000..5ec487e3f --- /dev/null +++ b/pkg/ingress/kube/kingress/resources/virtual_service.go @@ -0,0 +1,148 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "strings" + + "k8s.io/apimachinery/pkg/util/sets" + + istiov1alpha3 "istio.io/api/networking/v1alpha3" + "knative.dev/networking/pkg/apis/networking/v1alpha1" + "knative.dev/pkg/network" +) + +func MakeVirtualServiceRoute(hosts sets.String, http *v1alpha1.HTTPIngressPath) *istiov1alpha3.HTTPRoute { + matches := []*istiov1alpha3.HTTPMatchRequest{} + // Deduplicate hosts to avoid excessive matches, which cause a combinatorial expansion in Istio + + for _, host := range hosts.List() { + matches = append(matches, makeMatch(host, http.Path, http.Headers)) + } + + weights := []*istiov1alpha3.HTTPRouteDestination{} + for _, split := range http.Splits { + var h *istiov1alpha3.Headers + if len(split.AppendHeaders) > 0 { + h = &istiov1alpha3.Headers{ + Request: &istiov1alpha3.Headers_HeaderOperations{ + Set: split.AppendHeaders, + }, + } + } + + weights = append(weights, &istiov1alpha3.HTTPRouteDestination{ + Destination: &istiov1alpha3.Destination{ + Host: network.GetServiceHostname( + split.ServiceName, split.ServiceNamespace), + Port: &istiov1alpha3.PortSelector{ + Number: uint32(split.ServicePort.IntValue()), + }, + }, + Weight: int32(split.Percent), + Headers: h, + }) + } + + var h *istiov1alpha3.Headers + if len(http.AppendHeaders) > 0 { + h = &istiov1alpha3.Headers{ + Request: &istiov1alpha3.Headers_HeaderOperations{ + Set: http.AppendHeaders, + }, + } + } + + var rewrite *istiov1alpha3.HTTPRewrite + if http.RewriteHost != "" { + rewrite = &istiov1alpha3.HTTPRewrite{ + Authority: http.RewriteHost, + } + } + + route := &istiov1alpha3.HTTPRoute{ + Retries: &istiov1alpha3.HTTPRetry{}, // Override default istio behaviour of retrying twice. + Match: matches, + Route: weights, + Rewrite: rewrite, + Headers: h, + } + return route +} + +// getDistinctHostPrefixes deduplicate a set of prefix matches. For example, the set {a, aabb} can be +// reduced to {a}, as a prefix match on {a} accepts all the same inputs as {a, aabb}. +func getDistinctHostPrefixes(hosts sets.String) sets.String { + // First we sort the list. This ensures that we always process the smallest elements (which match against + // the most patterns, as they are less specific) first. + all := hosts.List() + ns := sets.NewString() + for _, h := range all { + prefixExists := false + h = hostPrefix(h) + // For each element, check if any existing elements are a prefix. We only insert if none are + // // For example, if we already have {a} and we are looking at "ab", we would not add it as it has a prefix of "a" + for e := range ns { + if strings.HasPrefix(h, e) { + prefixExists = true + break + } + } + if !prefixExists { + ns.Insert(h) + } + } + return ns +} + +func makeMatch(host, path string, headers map[string]v1alpha1.HeaderMatch) *istiov1alpha3.HTTPMatchRequest { + match := &istiov1alpha3.HTTPMatchRequest{ + Authority: &istiov1alpha3.StringMatch{ + // Do not use Regex as Istio 1.4 or later has 100 bytes limitation. + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: host}, + }, + } + // Empty path is considered match all path. We only need to consider path + // when it's non-empty. + if path != "" { + match.Uri = &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: path}, + } + } + + for k, v := range headers { + match.Headers = map[string]*istiov1alpha3.StringMatch{ + k: { + MatchType: &istiov1alpha3.StringMatch_Exact{ + Exact: v.Exact, + }, + }, + } + } + + return match +} + +// hostPrefix returns an host to match either host or host:. +// For clusterLocalHost, it trims .svc. from the host to match short host. +func hostPrefix(host string) string { + localDomainSuffix := ".svc." + network.GetClusterDomainName() + if !strings.HasSuffix(host, localDomainSuffix) { + return host + } + return strings.TrimSuffix(host, localDomainSuffix) +} diff --git a/pkg/ingress/kube/kingress/resources/virtual_service_test.go b/pkg/ingress/kube/kingress/resources/virtual_service_test.go new file mode 100644 index 000000000..07475b6d9 --- /dev/null +++ b/pkg/ingress/kube/kingress/resources/virtual_service_test.go @@ -0,0 +1,258 @@ +/* +Copyright 2019 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package resources + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" + istiov1alpha3 "istio.io/api/networking/v1alpha3" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/sets" + "knative.dev/networking/pkg/apis/networking/v1alpha1" + "knative.dev/pkg/system" + _ "knative.dev/pkg/system/testing" +) + +var ( + defaultIngressRuleValue = &v1alpha1.HTTPIngressRuleValue{ + Paths: []v1alpha1.HTTPIngressPath{{ + Splits: []v1alpha1.IngressBackendSplit{{ + Percent: 100, + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "test", + ServiceName: "test.svc.cluster.local", + ServicePort: intstr.FromInt(8080), + }, + }}, + }}, + } + defaultIngress = v1alpha1.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-ingress", + Namespace: system.Namespace(), + }, + Spec: v1alpha1.IngressSpec{Rules: []v1alpha1.IngressRule{{ + Hosts: []string{ + "test-route.test-ns.svc.cluster.local", + }, + HTTP: defaultIngressRuleValue, + }}}, + } + defaultVSCmpOpts = protocmp.Transform() +) + +func TestMakeVirtualServiceRoute_RewriteHost(t *testing.T) { + ingressPath := &v1alpha1.HTTPIngressPath{ + RewriteHost: "the.target.host", + Splits: []v1alpha1.IngressBackendSplit{{ + Percent: 100, + IngressBackend: v1alpha1.IngressBackend{ + ServiceName: "the-svc", + ServiceNamespace: "the-ns", + ServicePort: intstr.FromInt(8080), + }, + }}, + } + route := MakeVirtualServiceRoute(sets.NewString("a.vanity.url", "another.vanity.url"), ingressPath) + expected := &istiov1alpha3.HTTPRoute{ + Retries: &istiov1alpha3.HTTPRetry{}, + Match: []*istiov1alpha3.HTTPMatchRequest{{ + Authority: &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: `a.vanity.url`}, + }, + }, { + Authority: &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: `another.vanity.url`}, + }, + }}, + Rewrite: &istiov1alpha3.HTTPRewrite{ + Authority: "the.target.host", + }, + Route: []*istiov1alpha3.HTTPRouteDestination{{ + Destination: &istiov1alpha3.Destination{ + Host: "the-svc.the-ns.svc.cluster.local", + Port: &istiov1alpha3.PortSelector{ + Number: 8080, + }, + }, + Weight: 100, + }}, + } + if diff := cmp.Diff(expected, route, defaultVSCmpOpts); diff != "" { + t.Error("Unexpected route (-want +got):", diff) + } +} + +// One active target. +func TestMakeVirtualServiceRoute_Vanilla(t *testing.T) { + ingressPath := &v1alpha1.HTTPIngressPath{ + Headers: map[string]v1alpha1.HeaderMatch{ + "my-header": { + Exact: "my-header-value", + }, + }, + Splits: []v1alpha1.IngressBackendSplit{{ + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "test-ns", + ServiceName: "revision-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + } + route := MakeVirtualServiceRoute(sets.NewString("a.com", "b.org"), ingressPath) + expected := &istiov1alpha3.HTTPRoute{ + Retries: &istiov1alpha3.HTTPRetry{}, + Match: []*istiov1alpha3.HTTPMatchRequest{{ + Authority: &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: `a.com`}, + }, + Headers: map[string]*istiov1alpha3.StringMatch{ + "my-header": { + MatchType: &istiov1alpha3.StringMatch_Exact{ + Exact: "my-header-value", + }, + }, + }, + }, { + Authority: &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: `b.org`}, + }, + Headers: map[string]*istiov1alpha3.StringMatch{ + "my-header": { + MatchType: &istiov1alpha3.StringMatch_Exact{ + Exact: "my-header-value", + }, + }, + }, + }}, + Route: []*istiov1alpha3.HTTPRouteDestination{{ + Destination: &istiov1alpha3.Destination{ + Host: "revision-service.test-ns.svc.cluster.local", + Port: &istiov1alpha3.PortSelector{Number: 80}, + }, + Weight: 100, + }}, + } + if diff := cmp.Diff(expected, route, defaultVSCmpOpts); diff != "" { + t.Error("Unexpected route (-want +got):", diff) + } +} + +// One active target. +func TestMakeVirtualServiceRoute_Internal(t *testing.T) { + ingressPath := &v1alpha1.HTTPIngressPath{ + Splits: []v1alpha1.IngressBackendSplit{{ + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "test-ns", + ServiceName: "revision-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 100, + }}, + } + route := MakeVirtualServiceRoute(sets.NewString("a.default"), ingressPath) + expected := &istiov1alpha3.HTTPRoute{ + Retries: &istiov1alpha3.HTTPRetry{}, + Match: []*istiov1alpha3.HTTPMatchRequest{{ + Authority: &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: `a.default`}, + }, + }}, + Route: []*istiov1alpha3.HTTPRouteDestination{{ + Destination: &istiov1alpha3.Destination{ + Host: "revision-service.test-ns.svc.cluster.local", + Port: &istiov1alpha3.PortSelector{Number: 80}, + }, + Weight: 100, + }}, + } + if diff := cmp.Diff(expected, route, defaultVSCmpOpts); diff != "" { + t.Error("Unexpected route (-want +got):", diff) + } +} + +// Two active targets. +func TestMakeVirtualServiceRoute_TwoTargets(t *testing.T) { + ingressPath := &v1alpha1.HTTPIngressPath{ + Splits: []v1alpha1.IngressBackendSplit{{ + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "test-ns", + ServiceName: "revision-service", + ServicePort: intstr.FromInt(80), + }, + Percent: 90, + }, { + IngressBackend: v1alpha1.IngressBackend{ + ServiceNamespace: "test-ns", + ServiceName: "new-revision-service", + ServicePort: intstr.FromInt(81), + }, + Percent: 10, + }}, + } + route := MakeVirtualServiceRoute(sets.NewString("test.org"), ingressPath) + expected := &istiov1alpha3.HTTPRoute{ + Retries: &istiov1alpha3.HTTPRetry{}, + Match: []*istiov1alpha3.HTTPMatchRequest{{ + Authority: &istiov1alpha3.StringMatch{ + MatchType: &istiov1alpha3.StringMatch_Prefix{Prefix: `test.org`}, + }, + }}, + Route: []*istiov1alpha3.HTTPRouteDestination{{ + Destination: &istiov1alpha3.Destination{ + Host: "revision-service.test-ns.svc.cluster.local", + Port: &istiov1alpha3.PortSelector{Number: 80}, + }, + Weight: 90, + }, { + Destination: &istiov1alpha3.Destination{ + Host: "new-revision-service.test-ns.svc.cluster.local", + Port: &istiov1alpha3.PortSelector{Number: 81}, + }, + Weight: 10, + }}, + } + if diff := cmp.Diff(expected, route, defaultVSCmpOpts); diff != "" { + t.Error("Unexpected route (-want +got):", diff) + } +} + +func TestGetDistinctHostPrefixes(t *testing.T) { + cases := []struct { + name string + in sets.String + out sets.String + }{ + {"empty", sets.NewString(), sets.NewString()}, + {"single element", sets.NewString("a"), sets.NewString("a")}, + {"no overlap", sets.NewString("a", "b"), sets.NewString("a", "b")}, + {"overlap", sets.NewString("a", "ab", "abc"), sets.NewString("a")}, + {"multiple overlaps", sets.NewString("a", "ab", "abc", "xyz", "xy", "m"), sets.NewString("a", "xy", "m")}, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + got := getDistinctHostPrefixes(tt.in) + if !tt.out.Equal(got) { + t.Fatalf("Expected %v, got %v", tt.out, got) + } + }) + } +} diff --git a/pkg/ingress/kube/kingress/status.go b/pkg/ingress/kube/kingress/status.go new file mode 100644 index 000000000..22f0f790f --- /dev/null +++ b/pkg/ingress/kube/kingress/status.go @@ -0,0 +1,127 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// 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 kingress + +import ( + "context" + "reflect" + "time" + + coreV1 "k8s.io/api/core/v1" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + listerv1 "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" + "knative.dev/networking/pkg/apis/networking/v1alpha1" + kingressclient "knative.dev/networking/pkg/client/clientset/versioned" + kingresslister "knative.dev/networking/pkg/client/listers/networking/v1alpha1" + + common2 "github.com/alibaba/higress/pkg/ingress/kube/common" + . "github.com/alibaba/higress/pkg/ingress/log" + "github.com/alibaba/higress/pkg/kube" +) + +// statusSyncer keeps the status IP in each Ingress resource updated +type statusSyncer struct { + client kingressclient.Interface + controller *controller + watchedNamespace string + ingressLister kingresslister.IngressLister + serviceLister listerv1.ServiceLister +} + +// newStatusSyncer creates a new instance +func newStatusSyncer(localKubeClient, client kube.Client, controller *controller, namespace string) *statusSyncer { + return &statusSyncer{ + client: client.KIngress(), + controller: controller, + watchedNamespace: namespace, + ingressLister: client.KIngressInformer().Networking().V1alpha1().Ingresses().Lister(), + serviceLister: localKubeClient.KubeInformer().Core().V1().Services().Lister(), + } +} + +func (s *statusSyncer) run(stopCh <-chan struct{}) { + cache.WaitForCacheSync(stopCh, s.controller.HasSynced) + + ticker := time.NewTicker(common2.DefaultStatusUpdateInterval) + for { + select { + case <-stopCh: + ticker.Stop() + return + case <-ticker.C: + if err := s.runUpdateStatus(); err != nil { + IngressLog.Errorf("update status task fail, err %v", err) + } + } + } +} + +func (s *statusSyncer) runUpdateStatus() error { + svcList, err := s.serviceLister.Services(s.watchedNamespace).List(common2.SvcLabelSelector) + if err != nil { + return err + } + + IngressLog.Debugf("found number %d of svc", len(svcList)) + lbStatusList := common2.GetLbStatusList(svcList) + return s.updateStatus(lbStatusList) +} + +func transportLoadBalancerIngress(status []coreV1.LoadBalancerIngress) []v1alpha1.LoadBalancerIngressStatus { + var KnativeLBIngress []v1alpha1.LoadBalancerIngressStatus + for _, addr := range status { + KnativeIng := v1alpha1.LoadBalancerIngressStatus{ + IP: addr.IP, + Domain: addr.Hostname, + } + KnativeLBIngress = append(KnativeLBIngress, KnativeIng) + } + return KnativeLBIngress +} + +// updateStatus updates ingress status with the list of IP +func (s *statusSyncer) updateStatus(status []coreV1.LoadBalancerIngress) error { + ingressList, err := s.ingressLister.List(labels.Everything()) + if err != nil { + return err + } + for _, ingress := range ingressList { + shouldTarget, err := s.controller.shouldProcessIngress(ingress) + if err != nil { + IngressLog.Warnf("error determining whether should target ingress %s/%s within cluster %s for status update: %v", + ingress.Namespace, ingress.Name, s.controller.options.ClusterId, err) + return err + } + if !shouldTarget { + continue + } + ingress.Status.MarkNetworkConfigured() + KIngressStatus := transportLoadBalancerIngress(status) + if ingress.Status.PublicLoadBalancer == nil || len(ingress.Status.PublicLoadBalancer.Ingress) != len(KIngressStatus) || reflect.DeepEqual(ingress.Status.PublicLoadBalancer.Ingress, KIngressStatus) { + ingress.Status.ObservedGeneration = ingress.Generation + ingress.Status.MarkLoadBalancerReady(KIngressStatus, KIngressStatus) + IngressLog.Infof("Update Ingress %v/%v within cluster %s status", ingress.Namespace, ingress.Name, s.controller.options.ClusterId) + } + _, err = s.client.NetworkingV1alpha1().Ingresses(ingress.Namespace).UpdateStatus(context.TODO(), ingress, metaV1.UpdateOptions{}) + if err != nil { + IngressLog.Warnf("error updating ingress %s/%s within cluster %s status: %v", + ingress.Namespace, ingress.Name, s.controller.options.ClusterId, err) + } + } + + return nil +} diff --git a/pkg/ingress/translation/translation.go b/pkg/ingress/translation/translation.go new file mode 100644 index 000000000..457626735 --- /dev/null +++ b/pkg/ingress/translation/translation.go @@ -0,0 +1,204 @@ +// Copyright (c) 2022 Alibaba Group Holding Ltd. +// +// 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 translation + +import ( + "sync" + + "istio.io/istio/pilot/pkg/model" + "istio.io/istio/pkg/config" + "istio.io/istio/pkg/config/schema/collection" + "istio.io/istio/pkg/config/schema/gvk" + "k8s.io/client-go/tools/cache" + + ingressconfig "github.com/alibaba/higress/pkg/ingress/config" + "github.com/alibaba/higress/pkg/ingress/kube/common" + . "github.com/alibaba/higress/pkg/ingress/log" + "github.com/alibaba/higress/pkg/kube" +) + +var ( + _ model.ConfigStoreCache = &IngressTranslation{} + _ model.IngressStore = &IngressTranslation{} +) + +type IngressTranslation struct { + ingressConfig *ingressconfig.IngressConfig + kingressConfig *ingressconfig.KIngressConfig + mutex sync.RWMutex + higressRouteCache model.IngressRouteCollection + higressDomainCache model.IngressDomainCollection +} + +func NewIngressTranslation(localKubeClient kube.Client, XDSUpdater model.XDSUpdater, namespace, clusterId string) *IngressTranslation { + if clusterId == "Kubernetes" { + clusterId = "" + } + Config := &IngressTranslation{ + ingressConfig: ingressconfig.NewIngressConfig(localKubeClient, XDSUpdater, namespace, clusterId), + kingressConfig: ingressconfig.NewKIngressConfig(localKubeClient, XDSUpdater, namespace, clusterId), + } + return Config +} + +func (m *IngressTranslation) AddLocalCluster(options common.Options) (common.IngressController, common.KIngressController) { + if m.kingressConfig == nil { + return m.ingressConfig.AddLocalCluster(options), nil + } + return m.ingressConfig.AddLocalCluster(options), m.kingressConfig.AddLocalCluster(options) +} + +func (m *IngressTranslation) InitializeCluster(ingressController common.IngressController, kingressController common.KIngressController, stop <-chan struct{}) error { + if err := m.ingressConfig.InitializeCluster(ingressController, stop); err != nil { + return err + } + if kingressController == nil { + return nil + } + if err := m.kingressConfig.InitializeCluster(kingressController, stop); err != nil { + return err + } + return nil +} + +func (m *IngressTranslation) RegisterEventHandler(kind config.GroupVersionKind, f model.EventHandler) { + m.ingressConfig.RegisterEventHandler(kind, f) + if m.kingressConfig != nil { + m.kingressConfig.RegisterEventHandler(kind, f) + } +} + +func (m *IngressTranslation) HasSynced() bool { + m.mutex.RLock() + defer m.mutex.RUnlock() + if !m.ingressConfig.HasSynced() { + return false + } + if m.kingressConfig != nil { + if !m.kingressConfig.HasSynced() { + return false + } + } + + return true +} + +func (m *IngressTranslation) Run(stop <-chan struct{}) { + go m.ingressConfig.Run(stop) + if m.kingressConfig != nil { + go m.kingressConfig.Run(stop) + } +} + +func (m *IngressTranslation) SetWatchErrorHandler(f func(r *cache.Reflector, err error)) error { + m.ingressConfig.SetWatchErrorHandler(f) + if m.kingressConfig != nil { + m.kingressConfig.SetWatchErrorHandler(f) + } + return nil +} + +func (m *IngressTranslation) GetIngressRoutes() model.IngressRouteCollection { + m.mutex.RLock() + defer m.mutex.RUnlock() + ingressRouteCache := m.ingressConfig.GetIngressRoutes() + m.higressRouteCache = model.IngressRouteCollection{} + m.higressRouteCache.Invalid = append(m.higressRouteCache.Invalid, ingressRouteCache.Invalid...) + m.higressRouteCache.Valid = append(m.higressRouteCache.Valid, ingressRouteCache.Valid...) + if m.kingressConfig != nil { + kingressRouteCache := m.kingressConfig.GetIngressRoutes() + m.higressRouteCache.Invalid = append(m.higressRouteCache.Invalid, kingressRouteCache.Invalid...) + m.higressRouteCache.Valid = append(m.higressRouteCache.Valid, kingressRouteCache.Valid...) + } + + return m.higressRouteCache + +} + +func (m *IngressTranslation) GetIngressDomains() model.IngressDomainCollection { + m.mutex.RLock() + defer m.mutex.RUnlock() + ingressDomainCache := m.ingressConfig.GetIngressDomains() + + m.higressDomainCache = model.IngressDomainCollection{} + m.higressDomainCache.Invalid = append(m.higressDomainCache.Invalid, ingressDomainCache.Invalid...) + m.higressDomainCache.Valid = append(m.higressDomainCache.Valid, ingressDomainCache.Valid...) + if m.kingressConfig != nil { + kingressDomainCache := m.kingressConfig.GetIngressDomains() + m.higressDomainCache.Invalid = append(m.higressDomainCache.Invalid, kingressDomainCache.Invalid...) + m.higressDomainCache.Valid = append(m.higressDomainCache.Valid, kingressDomainCache.Valid...) + } + return m.higressDomainCache +} + +func (m *IngressTranslation) Schemas() collection.Schemas { + return common.IngressIR +} + +func (m *IngressTranslation) Get(typ config.GroupVersionKind, name, namespace string) *config.Config { + return nil +} + +func (m *IngressTranslation) List(typ config.GroupVersionKind, namespace string) ([]config.Config, error) { + if typ != gvk.Gateway && + typ != gvk.VirtualService && + typ != gvk.DestinationRule && + typ != gvk.EnvoyFilter && + typ != gvk.ServiceEntry && + typ != gvk.WasmPlugin { + return nil, common.ErrUnsupportedOp + } + + // Currently, only support list all namespaces gateways or virtualservices. + if namespace != "" { + IngressLog.Warnf("ingress store only support type %s of all namespace.", typ) + return nil, common.ErrUnsupportedOp + } + + ingressConfig, err := m.ingressConfig.List(typ, namespace) + if err != nil { + return nil, err + } + var higressConfig []config.Config + higressConfig = append(higressConfig, ingressConfig...) + if m.kingressConfig != nil { + kingressConfig, err := m.kingressConfig.List(typ, namespace) + if err != nil { + return nil, err + } + higressConfig = append(higressConfig, kingressConfig...) + } + return higressConfig, nil +} + +func (m *IngressTranslation) Create(config config.Config) (revision string, err error) { + return "", common.ErrUnsupportedOp +} + +func (m *IngressTranslation) Update(config config.Config) (newRevision string, err error) { + return "", common.ErrUnsupportedOp +} + +func (m *IngressTranslation) UpdateStatus(config config.Config) (newRevision string, err error) { + return "", common.ErrUnsupportedOp +} + +func (m *IngressTranslation) Patch(orig config.Config, patchFn config.PatchFunc) (string, error) { + return "", common.ErrUnsupportedOp +} + +func (m *IngressTranslation) Delete(typ config.GroupVersionKind, name, namespace string, resourceVersion *string) error { + return common.ErrUnsupportedOp +} diff --git a/pkg/kube/client.go b/pkg/kube/client.go index e6d463998..d3bedb508 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -15,21 +15,29 @@ package kube import ( + "context" "fmt" "reflect" "time" "go.uber.org/atomic" istiokube "istio.io/istio/pkg/kube" + apiExtensionsV1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/rest" clienttesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/clientcmd" + kingressclient "knative.dev/networking/pkg/client/clientset/versioned" + kingressfake "knative.dev/networking/pkg/client/clientset/versioned/fake" + kingressinformer "knative.dev/networking/pkg/client/informers/externalversions" higressclient "github.com/alibaba/higress/client/pkg/clientset/versioned" higressfake "github.com/alibaba/higress/client/pkg/clientset/versioned/fake" higressinformer "github.com/alibaba/higress/client/pkg/informers/externalversions" + "github.com/alibaba/higress/pkg/config/constants" ) type Client interface { @@ -40,6 +48,11 @@ type Client interface { // HigressInformer returns an informer for the higress client HigressInformer() higressinformer.SharedInformerFactory + + //KIngress return the Knative kube client + KIngress() kingressclient.Interface + + KIngressInformer() kingressinformer.SharedInformerFactory } type client struct { @@ -48,9 +61,12 @@ type client struct { higress higressclient.Interface higressInformer higressinformer.SharedInformerFactory + kingress kingressclient.Interface + kingressInformer kingressinformer.SharedInformerFactory // If enable, will wait for cache syncs with extremely short delay. This should be used only for tests - fastSync bool - informerWatchesPending *atomic.Int32 + fastSync bool + informerWatchesPending *atomic.Int32 + kinformerWatchesPending *atomic.Int32 } const resyncInterval = 0 @@ -62,7 +78,9 @@ func NewFakeClient(objects ...runtime.Object) Client { c.higress = higressfake.NewSimpleClientset() c.higressInformer = higressinformer.NewSharedInformerFactoryWithOptions(c.higress, resyncInterval) c.informerWatchesPending = atomic.NewInt32(0) - + c.kingress = kingressfake.NewSimpleClientset() + c.kingressInformer = kingressinformer.NewSharedInformerFactoryWithOptions(c.kingress, resyncInterval) + c.kinformerWatchesPending = atomic.NewInt32(0) // https://github.com/kubernetes/kubernetes/issues/95372 // There is a race condition in the client fakes, where events that happen between the List and Watch // of an informer are dropped. To avoid this, we explicitly manage the list and watch, ensuring all lists @@ -90,6 +108,27 @@ func NewFakeClient(objects ...runtime.Object) Client { fc := c.higress.(*higressfake.Clientset) fc.PrependReactor("list", "&", listReactor) fc.PrependWatchReactor("*", watchReactor(fc.Tracker())) + + klistReactor := func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { + c.kinformerWatchesPending.Inc() + return false, nil, nil + } + kwatchReactor := func(tracker clienttesting.ObjectTracker) func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) { + return func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := tracker.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + c.kinformerWatchesPending.Dec() + return true, watch, nil + } + } + fcknative := c.kingress.(*kingressfake.Clientset) + fcknative.PrependReactor("list", "&", klistReactor) + fcknative.PrependWatchReactor("*", kwatchReactor(fcknative.Tracker())) + c.fastSync = true return c } @@ -107,9 +146,28 @@ func NewClient(clientConfig clientcmd.ClientConfig) (Client, error) { return nil, err } c.higressInformer = higressinformer.NewSharedInformerFactory(c.higress, resyncInterval) + + c.kingress, err = kingressclient.NewForConfig(istioClient.RESTConfig()) + if err != nil { + return nil, err + } + if CheckKIngressCRDExist(istioClient.RESTConfig()) { + c.kingressInformer = kingressinformer.NewSharedInformerFactory(c.kingress, resyncInterval) + } else { + c.kingressInformer = nil + } + return &c, nil } +func (c *client) KIngress() kingressclient.Interface { + return c.kingress +} + +func (c *client) KIngressInformer() kingressinformer.SharedInformerFactory { + return c.kingressInformer +} + func (c *client) Higress() higressclient.Interface { return c.higress } @@ -121,6 +179,7 @@ func (c *client) HigressInformer() higressinformer.SharedInformerFactory { func (c *client) RunAndWait(stop <-chan struct{}) { c.Client.RunAndWait(stop) c.higressInformer.Start(stop) + if c.fastSync { fastWaitForCacheSync(stop, c.higressInformer) _ = wait.PollImmediate(time.Microsecond*100, wait.ForeverTestTimeout, func() (bool, error) { @@ -137,6 +196,27 @@ func (c *client) RunAndWait(stop <-chan struct{}) { } else { c.higressInformer.WaitForCacheSync(stop) } + + if c.kingressInformer != nil { + c.kingressInformer.Start(stop) + if c.fastSync { + fastWaitForCacheSync(stop, c.kingressInformer) + _ = wait.PollImmediate(time.Microsecond*100, wait.ForeverTestTimeout, func() (bool, error) { + select { + case <-stop: + return false, fmt.Errorf("channel closed") + default: + } + if c.informerWatchesPending.Load() == 0 { + return true, nil + } + return false, nil + }) + } else { + c.kingressInformer.WaitForCacheSync(stop) + } + } + } type reflectInformerSync interface { @@ -162,3 +242,23 @@ func fastWaitForCacheSync(stop <-chan struct{}, informerFactory reflectInformerS return true, nil }) } + +// Check Knative Ingress CRD +func CheckKIngressCRDExist(config *rest.Config) bool { + apiExtClientset, err := apiExtensionsV1.NewForConfig(config) + if err != nil { + fmt.Errorf("failed creating apiExtension Client: %v", err) + return false + } + crdList, err := apiExtClientset.CustomResourceDefinitions().List(context.TODO(), metaV1.ListOptions{}) + if err != nil { + fmt.Errorf("failed listing Custom Resource Definition: %v", err) + return false + } + for _, crd := range crdList.Items { + if crd.Name == constants.KnativeIngressCRDName { + return true + } + } + return false +}