diff --git a/.circleci/config.yml b/.circleci/config.yml index 73fa2d221..fecfe7722 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,8 +72,8 @@ jobs: password_variable: DOCKER_PASSWORD - prometheus/publish_images: container_image_name: comment-monitor - dockerfile_path: "tools/commentMonitor/Dockerfile" - dockerbuild_context: "tools/commentMonitor/" + dockerfile_path: "tools/comment-monitor/Dockerfile" + dockerbuild_context: "tools/comment-monitor/" registry: docker.io organization: "$DOCKER_ORG" login_variable: DOCKER_LOGIN diff --git a/.gitignore b/.gitignore index e6fc926e3..75366ffb3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .idea/ /tools/amGithubNotifier/amGithubNotifier -/tools/commentMonitor/commentMonitor +/tools/comment-monitor/comment-monitor /tools/fake-webserver/fake-webserver /tools/scaler/scaler /infra/infra diff --git a/.promu.yml b/.promu.yml index 2717b0de4..15d298366 100644 --- a/.promu.yml +++ b/.promu.yml @@ -10,8 +10,8 @@ build: path: ./infra - name: tools/amGithubNotifier path: ./tools/amGithubNotifier - - name: tools/commentMonitor - path: ./tools/commentMonitor + - name: tools/comment-monitor + path: ./tools/comment-monitor - name: tools/fake-webserver path: ./tools/fake-webserver - name: tools/scaler diff --git a/Makefile b/Makefile index 44885734b..f8479bc05 100644 --- a/Makefile +++ b/Makefile @@ -28,4 +28,21 @@ docs-check: generate-dashboards-cm: ./scripts/sync-dashboards-to-configmap.sh +GOIMPORTS = goimports +$(GOIMPORTS): + @go install golang.org/x/tools/cmd/goimports@latest + +GOFUMPT = gofumpt +$(GOFUMPT): + @go install mvdan.cc/gofumpt@latest + +GO_FILES = $(shell find . -path ./vendor -prune -o -name '*.go' -print) + +.PHONY: format +format: $(GOFUMPT) $(GOIMPORTS) + @echo ">> formating imports)" + @$(GOIMPORTS) -local github.com/prometheus/test-infra -w $(GO_FILES) + @echo ">> gofumpt-ing the code; golangci-lint requires this" + @$(GOFUMPT) -extra -w $(GO_FILES) + include Makefile.common diff --git a/go.mod b/go.mod index 2c33ea0e9..2cce8d52a 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( cloud.google.com/go/container v1.41.0 github.com/aws/aws-sdk-go v1.55.5 github.com/google/go-github/v29 v29.0.3 + github.com/nelkinda/health-go v0.0.1 github.com/prometheus/alertmanager v0.27.0 github.com/prometheus/client_golang v1.20.5 github.com/prometheus/common v0.60.1 @@ -18,7 +19,7 @@ require ( k8s.io/apiextensions-apiserver v0.31.2 k8s.io/apimachinery v0.31.2 k8s.io/client-go v0.31.2 - k8s.io/cloud-provider-gcp v0.0.0-20231031161848-992c1c33f1be + k8s.io/cloud-provider-gcp v0.0.0-20241115222652-d74b2e1d6653 sigs.k8s.io/aws-iam-authenticator v0.6.27 sigs.k8s.io/kind v0.25.0 ) @@ -58,6 +59,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mozillazg/go-httpheader v0.2.1 // indirect github.com/ncw/swift v1.0.53 // indirect + github.com/nelkinda/http-go v0.0.1 // indirect github.com/oracle/oci-go-sdk/v65 v65.41.1 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/rs/xid v1.5.0 // indirect @@ -100,7 +102,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.6.0 github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/s2a-go v0.1.8 // indirect @@ -131,7 +133,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect - github.com/oklog/run v1.1.0 // indirect + github.com/oklog/run v1.1.0 github.com/oklog/ulid v1.3.1 // indirect github.com/onsi/gomega v1.33.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -149,18 +151,18 @@ require ( github.com/thanos-io/objstore v0.0.0-20240913165201-fd105025a2e5 github.com/x448/float16 v0.8.4 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect - go.opentelemetry.io/otel v1.29.0 // indirect - go.opentelemetry.io/otel/metric v1.29.0 // indirect - go.opentelemetry.io/otel/trace v1.29.0 // indirect - golang.org/x/crypto v0.28.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect + go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/trace v1.30.0 // indirect + golang.org/x/crypto v0.31.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.30.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect - golang.org/x/text v0.19.0 // indirect + golang.org/x/sync v0.10.0 + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect @@ -175,3 +177,6 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +// Remove broken version. +exclude k8s.io/cloud-provider-gcp/providers v0.0.0-00010101000000-000000000000 diff --git a/go.sum b/go.sum index 868140479..1e645594e 100644 --- a/go.sum +++ b/go.sum @@ -77,9 +77,12 @@ github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4u github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/antchfx/xmlquery v1.2.4/go.mod h1:KQQuESaxSlqugE2ZBcM/qn+ebIpt+d+4Xx7YcSGAIrM= +github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/aslakhellesoy/gox v1.0.100/go.mod h1:AJl542QsKKG96COVsv0N74HHzVQgDIQPceVUh1aeU2M= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= @@ -123,6 +126,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/christianhujer/assert v0.0.2 h1:j+nZAzx9h4su7L8hw0NGdd93J1BtjwnTyp8jd4wiRXs= +github.com/christianhujer/assert v0.0.2/go.mod h1:yszWvVhUvkosrPxaPy9FqnC6XH16zFoFs8+hPXKs4ZQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -135,6 +140,11 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cucumber/gherkin-go/v11 v11.0.0/go.mod h1:CX33k2XU2qog4e+TFjOValoq6mIUq0DmVccZs238R9w= +github.com/cucumber/godog v0.9.0/go.mod h1:roWCHkpeK6UTOyIRRl7IR+fgfBeZ4vZR7OSq2J/NbM4= +github.com/cucumber/messages-go/v10 v10.0.1/go.mod h1:kA5T38CBlBbYLU12TIrJ4fk4wSkVVOgyh7Enyy8WnSg= +github.com/cucumber/messages-go/v10 v10.0.3/go.mod h1:9jMZ2Y8ZxjLY6TG2+x344nt5rXstVVDYSdS5ySfI1WY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -186,14 +196,40 @@ github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= +github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= +github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= +github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= +github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= @@ -227,6 +263,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= @@ -304,6 +341,7 @@ github.com/hashicorp/go-sockaddr v1.0.6 h1:RSG8rKU28VTUTvEKghe5gIhIQpv8evvNpnDEy github.com/hashicorp/go-sockaddr v1.0.6/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= @@ -314,15 +352,18 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible h1:tKTaPHNVwikS3I1rdyf1INNvgJXWSf/+TzqsiGbrgnQ= github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.3+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s= +github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -337,17 +378,23 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +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= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 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= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -358,6 +405,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= +github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -370,6 +419,7 @@ github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.72 h1:ZSbxs2BfJensLyHdVOgHv+pfmvxYraaUy07ER04dWnA= github.com/minio/minio-go/v7 v7.0.72/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -380,6 +430,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -389,6 +440,11 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/nelkinda/health-go v0.0.1 h1:HQJv+Bt9KWTCDZ9qzuGgZRaQBPsi+LAps8SP+T3DoD0= +github.com/nelkinda/health-go v0.0.1/go.mod h1:oNvFVrveHIH/xPW5DqjFfdtlyhLXHFmNzULgu1Lhs5M= +github.com/nelkinda/http-go v0.0.1 h1:RL3RttZzzs/kzQaVPmtv5dxMaWValqCqGNjCXyjPI1k= +github.com/nelkinda/http-go v0.0.1/go.mod h1:DxPiZGVufTVSeO63nmVR5QO01TmSC0HHtEIZTHL5QEk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= @@ -404,6 +460,7 @@ github.com/oracle/oci-go-sdk/v65 v65.41.1/go.mod h1:MXMLMzHnnd9wlpgadPkdlkZ9YrwQ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= @@ -448,6 +505,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= @@ -463,14 +522,18 @@ github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1 github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 h1:OfRzdxCzDhp+rsKWXuOO2I/quKMJ/+TQwVbIP/gltZg= github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92/go.mod h1:7/OT02F6S6I7v6WXb+IjhMuZEYfH/RJ5RwEWnEo5BMg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -481,6 +544,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -494,13 +558,17 @@ github.com/tencentyun/cos-go-sdk-v5 v0.7.40 h1:W6vDGKCHe4wBACI1d2UgE6+50sJFhRWU4 github.com/tencentyun/cos-go-sdk-v5 v0.7.40/go.mod h1:4dCEtLHGh8QPxHEkgq+nFaky7yZxQuYwgSJM87icDaw= github.com/thanos-io/objstore v0.0.0-20240913165201-fd105025a2e5 h1:sb2s6y+T5+iaNElATi4bpzw2lGMcd5YjAUvxQp9ePtw= github.com/thanos-io/objstore v0.0.0-20240913165201-fd105025a2e5/go.mod h1:A5Rlc/vdyENE5D0as6+6kp4kxWO72b4R0Q1ay/1d230= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= +github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -508,29 +576,32 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= +go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= +go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= +go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/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-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -585,6 +656,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -609,23 +681,27 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -660,33 +736,38 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= 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= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/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-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -819,6 +900,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -852,8 +934,8 @@ k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= -k8s.io/cloud-provider-gcp v0.0.0-20231031161848-992c1c33f1be h1:GIzgPD2/+Ci+p8ePVgY03rZQwsIq6A4XLf+IUbTHCY0= -k8s.io/cloud-provider-gcp v0.0.0-20231031161848-992c1c33f1be/go.mod h1:y7kgi9MMlMjhhNIlfFabXFp6s6gz7tOOWX1h9KtjmAE= +k8s.io/cloud-provider-gcp v0.0.0-20241115222652-d74b2e1d6653 h1:34dBv0GQgTaa0CH+Bcx0M0cISn2YKlp5rGiANnqiWnk= +k8s.io/cloud-provider-gcp v0.0.0-20241115222652-d74b2e1d6653/go.mod h1:prpAICgK0k6+hQSi7eqnmfuO/gBXP37L49p3TToSDR0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= diff --git a/prombench/design.svg b/prombench/design.svg index 131ddd42d..d5a76da3a 100644 --- a/prombench/design.svg +++ b/prombench/design.svg @@ -1,3 +1,3 @@ -
k8s Cluster
[Not supported by viewer]
GitHub
GitHub
    Main Node
    Main Node
Prometheus
(meta)
Prometheus<br>(meta)
Grafana
Grafana
CommentMonitor Webhook
/prombench master
/prombench v2.1.1
[Not supported by viewer]
pod
pod
k8s node


k8s node<br><br><br>
Alert Manager
Alert Manager<br>
Bench Node3


Bench Node3<br><br><br>
Bench Node 2



Bench Node 2<br><br><br><br>
Bench Node1
<span>Bench Node1</span>
Loadgen Scaler
Loadgen Scaler
Loadgen Querier
Loadgen Querier
Scale up & down
Scale up & down
Scrape via SD
<span>Scrape via SD</span>
Scrape query time
<span>Scrape query time</span>
Prometheus
( PR )
[Not supported by viewer]
Prometheus
( Release )

[Not supported by viewer]
Fake WebServers
Fake WebServers
GitHub Actions 
starts a new test
[Not supported by viewer]
Loki
(promtail pushes metrics to Loki)
[Not supported by viewer]
promtail
promtail
promtail
promtail
promtail
promtail
GitHub Notifier
Posts comments on alerts
[Not supported by viewer]
continuously scrape targets
continuously scrape targets
\ No newline at end of file +
k8s Cluster
[Not supported by viewer]
GitHub
GitHub
    Main Node
    Main Node
Prometheus
(meta)
Prometheus<br>(meta)
Grafana
Grafana
Comment Monitor Webhook
/prombench master
/prombench v2.1.1
[Not supported by viewer]
pod
pod
k8s node


k8s node<br><br><br>
Alert Manager
Alert Manager<br>
Bench Node3


Bench Node3<br><br><br>
Bench Node 2



Bench Node 2<br><br><br><br>
Bench Node1
<span>Bench Node1</span>
Loadgen Scaler
Loadgen Scaler
Loadgen Querier
Loadgen Querier
Scale up & down
Scale up & down
Scrape via SD
<span>Scrape via SD</span>
Scrape query time
<span>Scrape query time</span>
Prometheus
( PR )
[Not supported by viewer]
Prometheus
( Release )

[Not supported by viewer]
Fake WebServers
Fake WebServers
GitHub Actions 
starts a new test
[Not supported by viewer]
Loki
(promtail pushes metrics to Loki)
[Not supported by viewer]
promtail
promtail
promtail
promtail
promtail
promtail
GitHub Notifier
Posts comments on alerts
[Not supported by viewer]
continuously scrape targets
continuously scrape targets
diff --git a/prombench/manifests/cluster-infra/7a_commentmonitor_configmap_noparse.yaml b/prombench/manifests/cluster-infra/7a_commentmonitor_configmap_noparse.yaml index 1af4ff9c4..04b154183 100644 --- a/prombench/manifests/cluster-infra/7a_commentmonitor_configmap_noparse.yaml +++ b/prombench/manifests/cluster-infra/7a_commentmonitor_configmap_noparse.yaml @@ -5,55 +5,61 @@ metadata: data: config.yml: | prefixes: - - prefix: /prombench - help_template: | - Incorrect prombench syntax, please find [correct syntax here](https://github.com/prometheus/test-infra/tree/master/prombench#trigger-tests-via-a-github-comment). - verify_user: true - events: - - event_type: prombench_start - regex_string: (?mi)^/prombench\s*(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)\s*$ - label: prombench + - prefix: /prombench + help: | + **Available Commands:** + * To start benchmark: `/prombench ` + * To restart benchmark: `/prombench restart ` + * To stop benchmark: `/prombench cancel` + * To print help: `/prombench help` + + **Example:** `/prombench v3.0.0` + + verify_user: true + commands: + - name: cancel + event_type: prombench_stop comment_template: | - ⏱️ Welcome to Prometheus Benchmarking Tool. ⏱️ + Benchmark cancel is in progress. - **Compared versions:** [**`PR-{{ index . "PR_NUMBER" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-pr) and [**`{{ index . "RELEASE" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-release) + - name: restart + event_type: prombench_restart + args_regex: (?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$ + comment_template: | + ⏱️ Welcome (again) to Prometheus Benchmarking Tool. ⏱️ - After successful deployment, the benchmarking results can be viewed at: + **Compared versions:** [**`PR-{{ index . "PR_NUMBER" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-pr) and [**`{{ index . "RELEASE" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-release) + + After successful deployment ([check status here](https://github.com/prometheus/prometheus/actions/workflows/prombench.yml)), the benchmarking results can be viewed at: - [Prometheus Meta](http://{{ index . "DOMAIN_NAME" }}/prometheus-meta/graph?g0.expr={namespace%3D"prombench-{{ index . "PR_NUMBER" }}"}&g0.tab=1) - [Prombench Dashboard](http://{{ index . "DOMAIN_NAME" }}/grafana/d/7gmLoNDmz/prombench?orgId=1&var-pr-number={{ index . "PR_NUMBER" }}) - - [Grafana Explorer, Loki logs](http://{{ index . "DOMAIN_NAME" }}/grafana/explore?orgId=1&left=["now-6h","now","loki-meta",{},{"mode":"Logs"},{"ui":[true,true,true,"none"]}]) + - [Grafana Exlorer, Loki logs](http://{{ index . "DOMAIN_NAME" }}/grafana/explore?orgId=1&left=["now-6h","now","loki-meta",{},{"mode":"Logs"},{"ui":[true,true,true,"none"]}]) - [Parca profiles (e.g. in-use memory)](http://{{ index . "DOMAIN_NAME" }}/profiles?expression_a=memory%3Ainuse_space%3Abytes%3Aspace%3Abytes%7Bpr_number%3D%22{{ index . "PR_NUMBER" }}%22%7D&time_selection_a=relative:minute|15) - **Other Commands:** - To stop benchmark: `/prombench cancel` - To restart benchmark: `/prombench restart {{ index . "RELEASE" }}` - - - event_type: prombench_stop - regex_string: (?mi)^/prombench\s+cancel\s*$ - comment_template: | - Benchmark cancel is in progress. - - - event_type: noop - regex_string: (?mi)^/prombench\s*$ - comment_template: | - Please add the version number to compare against. - Eg. `/prombench main`, `/prombench v2.12.0` - - - event_type: prombench_restart - regex_string: (?mi)^/prombench\s+restart\s+(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)\s*$ + **Available Commands:** + * To restart benchmark: `/prombench restart {{ index . "RELEASE" }}` + * To stop benchmark: `/prombench cancel` + * To print help: `/prombench help` + + - name: "" # start is a default (empty command). + event_type: prombench_start + args_regex: (?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$ + label: prombench comment_template: | ⏱️ Welcome to Prometheus Benchmarking Tool. ⏱️ **Compared versions:** [**`PR-{{ index . "PR_NUMBER" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-pr) and [**`{{ index . "RELEASE" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-release) - After successful deployment, the benchmarking results can be viewed at: + After the successful deployment ([check status here](https://github.com/prometheus/prometheus/actions/workflows/prombench.yml)), the benchmarking results can be viewed at: - [Prometheus Meta](http://{{ index . "DOMAIN_NAME" }}/prometheus-meta/graph?g0.expr={namespace%3D"prombench-{{ index . "PR_NUMBER" }}"}&g0.tab=1) - [Prombench Dashboard](http://{{ index . "DOMAIN_NAME" }}/grafana/d/7gmLoNDmz/prombench?orgId=1&var-pr-number={{ index . "PR_NUMBER" }}) - - [Grafana Exlorer, Loki logs](http://{{ index . "DOMAIN_NAME" }}/grafana/explore?orgId=1&left=["now-6h","now","loki-meta",{},{"mode":"Logs"},{"ui":[true,true,true,"none"]}]) + - [Grafana Explorer, Loki logs](http://{{ index . "DOMAIN_NAME" }}/grafana/explore?orgId=1&left=["now-6h","now","loki-meta",{},{"mode":"Logs"},{"ui":[true,true,true,"none"]}]) - [Parca profiles (e.g. in-use memory)](http://{{ index . "DOMAIN_NAME" }}/profiles?expression_a=memory%3Ainuse_space%3Abytes%3Aspace%3Abytes%7Bpr_number%3D%22{{ index . "PR_NUMBER" }}%22%7D&time_selection_a=relative:minute|15) - **Other Commands:** - To stop benchmark: `/prombench cancel` - To restart benchmark: `/prombench restart {{ index . "RELEASE" }}` + **Available Commands:** + * To restart benchmark: `/prombench restart {{ index . "RELEASE" }}` + * To stop benchmark: `/prombench cancel` + * To print help: `/prombench help` + diff --git a/prombench/manifests/cluster-infra/7b_commentmonitor_deployment.yaml b/prombench/manifests/cluster-infra/7b_commentmonitor_deployment.yaml index d8429e63e..e00e803aa 100644 --- a/prombench/manifests/cluster-infra/7b_commentmonitor_deployment.yaml +++ b/prombench/manifests/cluster-infra/7b_commentmonitor_deployment.yaml @@ -19,7 +19,7 @@ spec: imagePullPolicy: Always args: - "--config=/etc/cm/config.yml" - - "--webhooksecretfile=/etc/github/whsecret" + - "--whsecret=/etc/github/whsecret" name: comment-monitor env: - name: DOMAIN_NAME @@ -47,7 +47,8 @@ spec: name: comment-monitor-config terminationGracePeriodSeconds: 300 nodeSelector: - node-name: main-node + cloud.google.com/gke-nodepool: main-node + --- apiVersion: v1 kind: Service diff --git a/scripts/genflagdocs.sh b/scripts/genflagdocs.sh index e45610e95..a1ce97f8b 100755 --- a/scripts/genflagdocs.sh +++ b/scripts/genflagdocs.sh @@ -10,7 +10,7 @@ SED_BIN=${SED_BIN:-sed} README_FILES="./tools/*/README.md ./infra/README.md" primary_tools=("infra") -helper_tools=("amGithubNotifier" "commentMonitor") +helper_tools=("amGithubNotifier" "comment-monitor") function fetch_embedmd { pushd .. diff --git a/tools/commentMonitor/Dockerfile b/tools/comment-monitor/Dockerfile similarity index 60% rename from tools/commentMonitor/Dockerfile rename to tools/comment-monitor/Dockerfile index f872fa9da..740242736 100644 --- a/tools/commentMonitor/Dockerfile +++ b/tools/comment-monitor/Dockerfile @@ -2,6 +2,6 @@ FROM quay.io/prometheus/busybox:latest LABEL maintainer="The Prometheus Authors " -COPY ./commentMonitor /bin/commentMonitor +COPY ./comment-monitor /bin/comment-monitor -ENTRYPOINT ["/bin/commentMonitor"] +ENTRYPOINT ["/bin/comment-monitor"] diff --git a/tools/commentMonitor/README.md b/tools/comment-monitor/README.md similarity index 74% rename from tools/commentMonitor/README.md rename to tools/comment-monitor/README.md index 11fe74ad1..f7093b2af 100644 --- a/tools/commentMonitor/README.md +++ b/tools/comment-monitor/README.md @@ -1,6 +1,12 @@ -# commentMonitor +# comment-monitor -A simple webhook server designed to parse GitHub comments and execute actions based on the comment content. Currently, it only supports the [`issue_comment` event](https://developer.github.com/v3/activity/events/types/#issuecommentevent) triggered by pull requests (PRs). +A GitHub webhook that watches GitHub Issue and Pull Request comments for `/prombench [] []` commands. + +On each command it dispatches appropriate [`repository_dispatch` event](https://developer.github.com/v3/repos/#create-a-repository-dispatch-event) to configured repository and notifies the same issue/PR. + +See [Prometheus GitHub action that responses to prombench comment-monitor dispatches](https://github.com/prometheus/prometheus/blob/main/.github/workflows/prombench.yml). + +Currently, it only supports the [`issue_comment` event](https://developer.github.com/v3/activity/events/types/#issuecommentevent), which can be triggered by either issue or PR. ## Table of Contents @@ -19,7 +25,7 @@ A simple webhook server designed to parse GitHub comments and execute actions ba ## Setting Up the Webhook Server -To specify the configuration file for `commentMonitor`, use the `--config` flag. +To specify the configuration file for `comment-monitor`, use the `--config` flag. ### Example `config.yml` File @@ -40,7 +46,7 @@ eventmaps: **How It Works:** - Comments are first checked to see if they start with any of the prefixes specified in `prefixes`. If not, the request is dropped. - If the prefix is matched, but the subsequent content does not match the `regex_string`, a comment with the `help_template` for that prefix is posted back to the issue/PR. -- If a comment matches the `regex_string`, `commentMonitor` will trigger a [`repository_dispatch` event](https://developer.github.com/v3/repos/#create-a-repository-dispatch-event) with the specified `event_type`. +- If a comment matches the `regex_string`, `comment-monitor` will trigger a [`repository_dispatch` event](https://developer.github.com/v3/repos/#create-a-repository-dispatch-event) with the specified `event_type`. - A comment will also be posted to the issue/PR with the `comment_template`. - Any arguments extracted by the `regex_string` will be passed to the [`client_payload`](https://developer.github.com/v3/repos/#example-5) of the `repository_dispatch` event. @@ -84,7 +90,7 @@ Flags: ## Building Docker Image -To build the Docker image for `commentMonitor`: +To build the Docker image for `comment-monitor`: ```bash docker build -t prominfra/comment-monitor:master . diff --git a/tools/comment-monitor/internal/command.go b/tools/comment-monitor/internal/command.go new file mode 100644 index 000000000..e2bb904c3 --- /dev/null +++ b/tools/comment-monitor/internal/command.go @@ -0,0 +1,217 @@ +// Copyright 2024 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +import ( + "errors" + "fmt" + "os" + "regexp" + "strings" + + "gopkg.in/yaml.v2" +) + +// Config allows defining custom commands that with their +// arguments. Those commands will be then parsed from GH issue comments, if +// anyone will comment with `/ ` line. +type Config struct { + Prefixes []*PrefixConfig `yaml:"prefixes"` +} + +func ParseConfig(file string) (*Config, error) { + data, err := os.ReadFile(file) + if err != nil { + return nil, fmt.Errorf("failed to read config file %v: %w", file, err) + } + return parseConfigContent(data) +} + +func parseConfigContent(content []byte) (_ *Config, err error) { + cfg := &Config{} + if err := yaml.UnmarshalStrict(content, cfg); err != nil { + return nil, fmt.Errorf("cannot unmarshal data: %w", err) + } + if len(cfg.Prefixes) == 0 { + return nil, errors.New("empty configuration; no prefix") + } + for _, p := range cfg.Prefixes { + if len(p.Commands) == 0 { + return nil, fmt.Errorf("empty configuration; no command for /%v", p.Prefix) + } + for _, c := range p.Commands { + if c.Name == "" && c.ArgsRegex == "" { + return nil, fmt.Errorf("/%v bad config; default commands cannot have empty args_regex (no required arguments)", p.Prefix) + } + if strings.HasPrefix(c.ArgsRegex, "^") { + return nil, fmt.Errorf("/%v bad config; args_regex has to be front open, got %v", p.Prefix, c.ArgsRegex) + } + + c.argsRegex, err = regexp.Compile(c.ArgsRegex) + if err != nil { + return nil, fmt.Errorf("/%v bad config; command %v args_regex %v doesn't compile: %w", p.Prefix, c.Name, c.ArgsRegex, err) + } + + commandArgsNames := c.argsRegex.SubexpNames()[1:] + for _, argName := range commandArgsNames { + if argName == "" { + return nil, fmt.Errorf("/%v bad config; command %v named groups in regex are mandatory; got %v", p.Prefix, c.Name, c.ArgsRegex) + } + } + } + } + return cfg, nil +} + +type PrefixConfig struct { + Prefix string `yaml:"prefix"` + Help string `yaml:"help"` + VerifyUser bool `yaml:"verify_user"` + Commands []*CommandConfig `yaml:"commands"` +} + +type CommandConfig struct { + Name string `yaml:"name"` + EventType string `yaml:"event_type"` + CommentTemplate string `yaml:"comment_template"` + ArgsRegex string `yaml:"args_regex"` + Label string `yaml:"label"` + + argsRegex *regexp.Regexp +} + +// Command represents a read-only, parsed command to dispatch with +// additional details for the GH comment update. +type Command struct { + Prefix string + EventType string + Args map[string]string + + ShouldVerifyUser bool + SuccessCommentTemplate string + SuccessLabel string + + DebugCMDLine string +} + +type CommandParseError struct { + error + help string +} + +func (c *CommandParseError) ToComment() string { + return c.help +} + +func hasExactPrefix(s, token string) bool { + return s == token || strings.HasPrefix(s, token+" ") || strings.HasPrefix(s, token+"\n") +} + +// ParseCommand parses command to dispatch from the issue comment, given the provided configuration. +func ParseCommand(cfg *Config, comment string) (_ *Command, ok bool, err *CommandParseError) { + comment = strings.TrimSpace(comment) + + // TODO(bwplotka): Consider accepting things before / 0 { + rest = rest[len(cmdConfig.Name)+1:] // plus prefixed space. + } + + if cmdConfig.ArgsRegex == "" { + // Ensure there are no more characters. + if len(rest) > 0 { + return nil, false, &CommandParseError{ + error: fmt.Errorf("command expected no argument, but got some '%v' for cmdLine: '%v'", rest, cmdLine), + help: fmt.Sprintf("Incorrect `%v` syntax; %v command expects no arguments, but got some.\n\n%s", prefix.Prefix, cmdConfig.Name, prefix.Help), + } + } + return cmd, true, nil + } + // Parse required arguments. + if !cmdConfig.argsRegex.MatchString(rest) { + return nil, false, &CommandParseError{ + error: fmt.Errorf("command requires at least one argument, matching '%v' regex on '%v' string for cmdLine '%v'", cmdConfig.ArgsRegex, rest, cmdLine), + help: fmt.Sprintf("Incorrect `%v` syntax; %v command requires at least one argument that matches `%v` regex.\n\n%s", prefix.Prefix, cmdConfig.Name, cmdConfig.ArgsRegex, prefix.Help), + } + } + + args := cmdConfig.argsRegex.FindStringSubmatch(rest)[1:] + commandArgsNames := cmdConfig.argsRegex.SubexpNames()[1:] + for i, argName := range commandArgsNames { + if argName == "" { + return nil, false, &CommandParseError{ + error: fmt.Errorf("named groups in regex are mandatory; should be validated on config read, got %v", cmdConfig.ArgsRegex), + } + } + cmd.Args[argName] = args[i] + } + return cmd, true, nil +} diff --git a/tools/comment-monitor/internal/command_test.go b/tools/comment-monitor/internal/command_test.go new file mode 100644 index 000000000..b5ff64901 --- /dev/null +++ b/tools/comment-monitor/internal/command_test.go @@ -0,0 +1,232 @@ +// Copyright 2024 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package internal + +import ( + "os" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "gopkg.in/yaml.v2" +) + +const ( + eventTypeStart = "prombench_start" + eventTypeRestart = "prombench_restart" + eventTypeStop = "prombench_stop" +) + +func testCommand(evenType, release string) *Command { + c := &Command{ + Prefix: "/prombench", + Args: map[string]string{}, + EventType: evenType, + ShouldVerifyUser: true, + } + if release != "" { + c.Args["RELEASE"] = release + } + return c +} + +type parseCommandCase struct { + comment string + expect *Command + expectErrCommentPrefix string +} + +func testParseCommand(t *testing.T, c *Config, cases []parseCommandCase) { + t.Helper() + + for _, tcase := range cases { + t.Run(tcase.comment, func(t *testing.T) { + cmd, found, pErr := ParseCommand(c, tcase.comment) + + // Incorrect syntax cases. + if tcase.expectErrCommentPrefix != "" { + if found == true { + t.Fatal("expected not found, got true") + } + if pErr == nil { + t.Fatal("expected error, got nil and found=", found) + } + if !strings.HasPrefix(pErr.ToComment(), tcase.expectErrCommentPrefix) { + t.Fatalf("Error comment does not match expected prefix:\n%s\n\ncomment:\n%s", tcase.expectErrCommentPrefix, pErr.ToComment()) + } + return + } + + if pErr != nil { + t.Fatalf("expected no error, got %q", pErr) + } + + // Triggering event cases. + if tcase.expect != nil { + if found == false { + t.Fatal("expected found, got false") + } + if cmd == nil { + t.Fatal("expected command, got nil") + } + // Don't test those fields for now. + cmd.SuccessCommentTemplate = "" + cmd.DebugCMDLine = "" + cmd.SuccessLabel = "" + if diff := cmp.Diff(*cmd, *tcase.expect); diff != "" { + t.Fatalf("-expect vs +got: %v", diff) + } + return + } + + // Not matching cases. + if found == true { + t.Fatal("expected not found, got true") + } + }) + } +} + +func TestParseCommand(t *testing.T) { + const testConfigFile = "./testconfig.yaml" + + c, err := ParseConfig(testConfigFile) + if err != nil { + t.Fatal(err) + } + testParseCommand(t, c, []parseCommandCase{ + { + comment: "/prombench", + expectErrCommentPrefix: "Incorrect `/prombench` syntax; no matching command found.", + }, + { + comment: "/prombench v3.0.0", + expect: testCommand(eventTypeStart, "v3.0.0"), + }, + { + comment: "/prombench restart v3.0.0", + expect: testCommand(eventTypeRestart, "v3.0.0"), + }, + { + comment: "/prombench cancel", + expect: testCommand(eventTypeStop, ""), + }, + // Different versions based on the provided args_regex: ^\s+(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)\s*$ + { + comment: "/prombench main", + expect: testCommand(eventTypeStart, "main"), + }, + // Text at the end is generally accepted, after \n. + { + comment: "/prombench v3.0.0\n", + expect: testCommand(eventTypeStart, "v3.0.0"), + }, + { + comment: "/prombench v3.0.0\n\nYolo", + expect: testCommand(eventTypeStart, "v3.0.0"), + }, + // Incorrect syntax cases. + { + comment: "/prombench v3.0.0 garbage", + expectErrCommentPrefix: "Incorrect `/prombench` syntax; command requires at least one argument that matches `" + `(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$` + "` regex.", + }, + { + comment: "/prombench restart v3.0.0 garbage", + expectErrCommentPrefix: "Incorrect `/prombench` syntax; restart command requires at least one argument that matches `" + `(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$` + "` regex.", + }, + { + comment: "/prombench restartv3.0.0 garbage", + expectErrCommentPrefix: "Incorrect `/prombench` syntax; command requires at least one argument that matches `" + `(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$` + "` regex.", + }, + { + comment: "/prombench cancel garbage", + expectErrCommentPrefix: "Incorrect `/prombench` syntax; cancel command expects no arguments, but got some.", + }, + { + comment: "/prombench not-a-version", + expectErrCommentPrefix: "Incorrect `/prombench` syntax; command requires at least one argument that matches `" + `(?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$` + "` regex.", + }, + // Not matching cases. + {comment: ""}, + {comment: "How to start prombench?\nyolo\nthanks"}, + // Space has to be used between prefix and command. + {comment: "/prombenchv3.0.0"}, + {comment: "/prombenchv3.0.0 v3.0.0"}, + {comment: "/prombenchcancel"}, + // Text in the front is not matching prombench. + // TODO(bwplotka): Consider accepting things before /` + * To restart benchmark: `/prombench restart ` + * To stop benchmark: `/prombench cancel` + * To print help: `/prombench help` + + **Example:** `/prombench v3.0.0` + + > NOTE: Validation of arguments are on prombench GitHub action time, not webhook time. + + verify_user: true + commands: + - name: cancel + event_type: prombench_stop + comment_template: | + Benchmark cancel is in progress. + + - name: restart + event_type: prombench_restart + args_regex: (?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$ + comment_template: | + ⏱️ Welcome (again) to Prometheus Benchmarking Tool. ⏱️ + + **Compared versions:** [**`PR-{{ index . "PR_NUMBER" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-pr) and [**`{{ index . "RELEASE" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-release) + + After successful deployment, the benchmarking results can be viewed at: + + - [Prometheus Meta](http://{{ index . "DOMAIN_NAME" }}/prometheus-meta/graph?g0.expr={namespace%3D"prombench-{{ index . "PR_NUMBER" }}"}&g0.tab=1) + - [Prombench Dashboard](http://{{ index . "DOMAIN_NAME" }}/grafana/d/7gmLoNDmz/prombench?orgId=1&var-pr-number={{ index . "PR_NUMBER" }}) + - [Grafana Exlorer, Loki logs](http://{{ index . "DOMAIN_NAME" }}/grafana/explore?orgId=1&left=["now-6h","now","loki-meta",{},{"mode":"Logs"},{"ui":[true,true,true,"none"]}]) + - [Parca profiles (e.g. in-use memory)](http://{{ index . "DOMAIN_NAME" }}/profiles?expression_a=memory%3Ainuse_space%3Abytes%3Aspace%3Abytes%7Bpr_number%3D%22{{ index . "PR_NUMBER" }}%22%7D&time_selection_a=relative:minute|15) + + **Available Commands:** + * To restart benchmark: `/prombench restart {{ index . "RELEASE" }}` + * To stop benchmark: `/prombench cancel` + * To print help: `/prombench help` + + - name: "" # start is a default (empty command). + event_type: prombench_start + args_regex: (?Pmaster|main|v[0-9]+\.[0-9]+\.[0-9]+\S*)$ + label: prombench + comment_template: | + ⏱️ Welcome to Prometheus Benchmarking Tool. ⏱️ + + **Compared versions:** [**`PR-{{ index . "PR_NUMBER" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-pr) and [**`{{ index . "RELEASE" }}`**](http://{{ index . "DOMAIN_NAME" }}/{{ index . "PR_NUMBER" }}/prometheus-release) + + After successful deployment, the benchmarking results can be viewed at: + + - [Prometheus Meta](http://{{ index . "DOMAIN_NAME" }}/prometheus-meta/graph?g0.expr={namespace%3D"prombench-{{ index . "PR_NUMBER" }}"}&g0.tab=1) + - [Prombench Dashboard](http://{{ index . "DOMAIN_NAME" }}/grafana/d/7gmLoNDmz/prombench?orgId=1&var-pr-number={{ index . "PR_NUMBER" }}) + - [Grafana Explorer, Loki logs](http://{{ index . "DOMAIN_NAME" }}/grafana/explore?orgId=1&left=["now-6h","now","loki-meta",{},{"mode":"Logs"},{"ui":[true,true,true,"none"]}]) + - [Parca profiles (e.g. in-use memory)](http://{{ index . "DOMAIN_NAME" }}/profiles?expression_a=memory%3Ainuse_space%3Abytes%3Aspace%3Abytes%7Bpr_number%3D%22{{ index . "PR_NUMBER" }}%22%7D&time_selection_a=relative:minute|15) + + **Available Commands:** + * To restart benchmark: `/prombench restart {{ index . "RELEASE" }}` + * To stop benchmark: `/prombench cancel` + * To print help: `/prombench help` diff --git a/tools/comment-monitor/main.go b/tools/comment-monitor/main.go new file mode 100644 index 000000000..dfa048d8a --- /dev/null +++ b/tools/comment-monitor/main.go @@ -0,0 +1,301 @@ +// Copyright 2019 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "context" + "fmt" + "io" + "log" + "log/slog" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "syscall" + "text/template" + + "github.com/google/go-github/v29/github" + "github.com/nelkinda/health-go" + "github.com/oklog/run" + "golang.org/x/sync/singleflight" + "gopkg.in/alecthomas/kingpin.v2" + + "github.com/prometheus/test-infra/tools/comment-monitor/internal" +) + +func main() { + var configFile, whSecretFile, listenPort, logLevelStr string + + app := kingpin.New(filepath.Base(os.Args[0]), "comment-monitor: A GH webhook "+ + "that watches GH Issue (and PR) comments for '/ [] [] []'"+ + "commands. On each command, it dispatches appropriate command as an event to GitHub repository API and notifies the same issue/PR.") + app.HelpFlag.Short('h') + app.Flag("config", "Path to the config file."). + Default("./config.yml"). + StringVar(&configFile) + app.Flag("whsecret", "Path to the webhook secret file for the payload signature validation."). + Default("./whsecret"). + StringVar(&whSecretFile) + app.Flag("port", "Port number to run webhook on."). + Default("8080"). + StringVar(&listenPort) + app.Flag("log.level", "Logging level, available values: 'debug', 'info', 'warn', 'error'."). + Default("info"). + StringVar(&logLevelStr) + kingpin.MustParse(app.Parse(os.Args[1:])) + + var logLevel slog.Level + if err := logLevel.UnmarshalText([]byte(logLevelStr)); err != nil { + log.Fatal("failed to parse -log.level flag", err) + } + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel})) + + d := newDispatcher(logger, configFile, whSecretFile) + mux := http.NewServeMux() + mux.HandleFunc("/", d.HandleIssue) // Issue means both GitHub Issue and PR. + + healthHandler := health.New(health.Health{}).Handler + mux.HandleFunc("/-/health", healthHandler) + mux.HandleFunc("/-/ready", healthHandler) + + var g run.Group + { + addr := fmt.Sprintf(":%v", listenPort) + httpSrv := &http.Server{Addr: addr, Handler: mux} + + g.Add(func() error { + logger.Info("server is ready to handle requests", "address", addr) + return httpSrv.ListenAndServe() + }, func(_ error) { + _ = httpSrv.Shutdown(context.Background()) + }) + } + g.Add(run.SignalHandler(context.Background(), os.Interrupt, syscall.SIGTERM)) + if err := g.Run(); err != nil { + logger.Error("running comment-monitor failed", "err", err) + os.Exit(1) + } + logger.Info("sink finished") +} + +type dispatcher struct { + logger *slog.Logger + configFile, whSecretFile string + + sfg singleflight.Group +} + +func newDispatcher(logger *slog.Logger, configFile, whSecretFile string) *dispatcher { + return &dispatcher{logger: logger, configFile: configFile, whSecretFile: whSecretFile} +} + +func (d *dispatcher) readConfigAndSecrets() (*internal.Config, []byte, string, error) { + type result struct { + cfg *internal.Config + whSecret []byte + ghToken string + } + + // Do it under a singleflight, as there's no + // need for concurrent requests to re-read files in the same time. + res, err, _ := d.sfg.Do("config-and-secret", func() (_ any, err error) { + r := result{} + + // Get a fresh config. + r.cfg, err = internal.ParseConfig(d.configFile) + if err != nil { + return nil, err + } + + // Get a fresh webhook secret. + r.whSecret, err = os.ReadFile(d.whSecretFile) + if err != nil { + return nil, err + } + + // Get a fresh GH token. + r.ghToken = os.Getenv("GITHUB_TOKEN") + if r.ghToken == "" { + return nil, fmt.Errorf("GITHUB_TOKEN env var missing") + } + return r, nil + }) + return res.(result).cfg, res.(result).whSecret, res.(result).ghToken, err +} + +func handleErr(w http.ResponseWriter, logger *slog.Logger, errMsg string, statusCode int, err error) { + logger.With("err", err, "code", statusCode).Error(errMsg) + http.Error(w, errMsg, statusCode) +} + +func (d *dispatcher) HandleIssue(w http.ResponseWriter, r *http.Request) { + defer func() { + _, _ = io.Copy(io.Discard, r.Body) + _ = r.Body.Close() + }() + + logger := d.logger + reqID := r.Header.Get("X-GitHub-Delivery") + if reqID != "" { + logger = logger.With("reqID", reqID) + } + + // Get fresh a configuration and secret on every request. + cfg, whSecret, ghToken, err := d.readConfigAndSecrets() + if err != nil { + handleErr(w, logger, "configuration or secrets are incorrect", http.StatusInternalServerError, err) + return + } + + // Validate payload, including its signature using the secret. + payload, err := github.ValidatePayload(r, whSecret) + if err != nil { + handleErr(w, logger, "failed to validate webhook payload", http.StatusBadRequest, err) + return + } + + // Parse webhook event. + event, err := github.ParseWebHook(github.WebHookType(r), payload) + if err != nil { + handleErr(w, logger, "failed to parse GH event payload", http.StatusBadRequest, err) + return + } + + e, ok := event.(*github.IssueCommentEvent) + if !ok { + logger := logger.With("eventType", fmt.Sprintf("%T", event)) + handleErr(w, logger, "only issue_comment event is supported", http.StatusBadRequest, err) + return + } + + if *e.Action != "created" { + logger.Debug("issue_comment type must be 'created', updates/edits are not supported", "action", *e.Action) + http.Error(w, "issue_comment type must be 'created'", http.StatusOK) // Using http.Error as a nice text response util. + return + } + + eventDetails := internal.NewEventDetails(e) + ghClient, err := internal.NewGithubClient(r.Context(), ghToken, eventDetails) + if err != nil { + handleErr(w, logger, "could not create GitHub client against the given repository", http.StatusBadRequest, err) + return + } + + logger = logger.With("repo", eventDetails.Repo, "issue", eventDetails.PR, "author", eventDetails.Author) + + cmd, found, parseErr := internal.ParseCommand(cfg, e.GetComment().GetBody()) + if parseErr != nil { + if comment := parseErr.ToComment(); comment != "" { + if postErr := ghClient.PostComment(comment); postErr != nil { + logger := logger.With("postErr", postErr) + handleErr(w, logger, "could not post comment to GitHub on failed command parsing", http.StatusBadRequest, parseErr) + return + } + } + // TODO(bwplotka) Post comment about this failure? + handleErr(w, logger, "parsing command from comment failed", http.StatusBadRequest, err) + return + } + + if !found { + logger.Debug("issue does not contain any command") + http.Error(w, "not a command", http.StatusOK) // Using http.Error as a nice text response util. + return + } + + // Verify user if configured. + if cmd.ShouldVerifyUser { + var allowed bool + allowedAssociations := []string{"COLLABORATOR", "MEMBER", "OWNER"} + for _, a := range allowedAssociations { + if a == eventDetails.AuthorAssociation { + allowed = true + } + } + if !allowed { + b := fmt.Sprintf("@%s is not a org member nor a collaborator and cannot execute benchmarks.", eventDetails.Author) + logger := logger.With("allowed", strings.Join(allowedAssociations, ",")) + if err := ghClient.PostComment(b); err != nil { + handleErr(w, logger, "user not allowed to run command; also could not post comment to GitHub", http.StatusForbidden, err) + } else { + handleErr(w, logger, "user not allowed to run command", http.StatusForbidden, nil) + } + return + } + + logger = logger.With("cmdLine", cmd.DebugCMDLine) + logger.Info("dispatching a new command and updating issue") + + // Combine all arguments for both dispatch and the comment update. + allArgs := cmd.Args + allArgs["PR_NUMBER"] = strconv.Itoa(eventDetails.PR) + allArgs["LAST_COMMIT_SHA"], err = ghClient.GetLastCommitSHA() + if err != nil { + // TODO(bwplotka) Post comment about this failure? + handleErr(w, logger, "could not fetch SHA, which likely means it's an issue, not a pull request. Non-PRs are not supported.", http.StatusBadRequest, err) + return + } + + logger = logger.With("evenType", cmd.EventType, "args", fmt.Sprintf("%v", allArgs)) + if err = ghClient.Dispatch(cmd.EventType, allArgs); err != nil { + // TODO(bwplotka) Post comment about this failure? + handleErr(w, logger, "could not dispatch", http.StatusInternalServerError, err) + return + } + logger.Info("dispatched repository GitHub payload") + + // Update the issue. + comment, err := executeCommentTemplate(cmd.SuccessCommentTemplate, allArgs) + if err != nil { + handleErr(w, logger, "failed to execute template", http.StatusInternalServerError, err) + return + } + + if err = ghClient.PostComment(comment); err != nil { + handleErr(w, logger, "dispatch successful; but could not post comment to GitHub", http.StatusInternalServerError, err) + return + } + + if cmd.SuccessLabel != "" { + if err = ghClient.PostLabel(cmd.SuccessLabel); err != nil { + handleErr(w, logger, "dispatch successful; but could not post label to GitHub", http.StatusInternalServerError, err) + return + } + } + } +} + +func executeCommentTemplate(commentTemplate string, args map[string]string) (string, error) { + argsCpy := make(map[string]string, len(args)) // TODO(bwplotka): Looks unsafe, we might want to type the known options. + if len(args) > 0 { + for k, v := range args { + argsCpy[k] = v + } + } + for _, e := range os.Environ() { + tmp := strings.Split(e, "=") + argsCpy[tmp[0]] = tmp[1] + } + + // Generate the comment template. + var buf bytes.Buffer + ct := template.Must(template.New("Comment").Parse(commentTemplate)) + if err := ct.Execute(&buf, argsCpy); err != nil { + return "", fmt.Errorf("templating failed: %w", err) + } + return buf.String(), nil +} diff --git a/tools/commentMonitor/client.go b/tools/commentMonitor/client.go deleted file mode 100644 index a3298858a..000000000 --- a/tools/commentMonitor/client.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2019 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "fmt" - "log" - "os" - "regexp" - "strconv" - "strings" - "text/template" -) - -type commentMonitorClient struct { - ghClient *githubClient - allArgs map[string]string - regex *regexp.Regexp - events []webhookEvent - prefixes []commandPrefix - helpTemplate string - shouldVerifyUser bool - eventType string - commentTemplate string - label string -} - -// Set eventType and commentTemplate if -// regexString is validated against provided command. -func (c *commentMonitorClient) validateRegex(command string) bool { - for _, e := range c.events { - c.regex = regexp.MustCompile(e.RegexString) - if c.regex.MatchString(command) { - c.commentTemplate = e.CommentTemplate - c.eventType = e.EventType - c.label = e.Label - log.Println("comment validation successful") - return true - } - } - return false -} - -func (c *commentMonitorClient) checkCommandPrefix(command string) bool { - for _, p := range c.prefixes { - if strings.HasPrefix(command, p.Prefix) { - c.helpTemplate = p.HelpTemplate - c.shouldVerifyUser = p.VerifyUser - return true - } - } - return false -} - -// Verify if user is allowed to perform activity. -func (c commentMonitorClient) verifyUser() error { - if c.shouldVerifyUser { - var allowed bool - allowedAssociations := []string{"COLLABORATOR", "MEMBER", "OWNER"} - for _, a := range allowedAssociations { - if a == c.ghClient.authorAssociation { - allowed = true - } - } - if !allowed { - b := fmt.Sprintf("@%s is not a org member nor a collaborator and cannot execute benchmarks.", c.ghClient.author) - if err := c.ghClient.postComment(b); err != nil { - return fmt.Errorf("%w : couldn't post comment", err) - } - return fmt.Errorf("author is not a member or collaborator") - } - log.Println("author is a member or collaborator") - } - return nil -} - -// Extract args if regexString provided. -func (c *commentMonitorClient) extractArgs(command string) error { - var err error - if c.regex != nil { - // Add command arguments. - commandArgs := c.regex.FindStringSubmatch(command)[1:] - commandArgsNames := c.regex.SubexpNames()[1:] - for i, argName := range commandArgsNames { - if argName == "" { - return fmt.Errorf("using named groups is mandatory") - } - c.allArgs[argName] = commandArgs[i] - } - - // Add non-comment arguments if any. - c.allArgs["PR_NUMBER"] = strconv.Itoa(c.ghClient.pr) - c.allArgs["LAST_COMMIT_SHA"], err = c.ghClient.getLastCommitSHA() - if err != nil { - return fmt.Errorf("%w: could not fetch SHA", err) - } - - // TODO (geekodour) : We could run this in a separate method. - err = c.ghClient.createRepositoryDispatch(c.eventType, c.allArgs) - if err != nil { - return fmt.Errorf("%w: could not create repository_dispatch event", err) - } - } - return nil -} - -func (c commentMonitorClient) postLabel() error { - if c.label != "" { - if err := c.ghClient.createLabel(c.label); err != nil { - return fmt.Errorf("%w : couldn't set label", err) - } - log.Println("label successfully set") - } - return nil -} - -func (c commentMonitorClient) generateAndPostSuccessComment() error { - return c.generateAndPostComment(c.commentTemplate) -} - -func (c commentMonitorClient) generateAndPostErrorComment() error { - return c.generateAndPostComment(c.helpTemplate) -} - -func (c commentMonitorClient) generateAndPostComment(commentTemplate string) error { - if commentTemplate != "" { - // Add all env vars to allArgs. - for _, e := range os.Environ() { - tmp := strings.Split(e, "=") - c.allArgs[tmp[0]] = tmp[1] - } - // Generate the comment template. - var buf bytes.Buffer - ct := template.Must(template.New("Comment").Parse(commentTemplate)) - if err := ct.Execute(&buf, c.allArgs); err != nil { - return err - } - // Post the comment. - if err := c.ghClient.postComment(buf.String()); err != nil { - return fmt.Errorf("%w : couldn't post generated comment", err) - } - log.Println("comment successfully posted") - } - return nil -} diff --git a/tools/commentMonitor/ghclient.go b/tools/commentMonitor/ghclient.go deleted file mode 100644 index a8154ccfc..000000000 --- a/tools/commentMonitor/ghclient.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "encoding/json" - "fmt" - "log" - "os" - - "github.com/google/go-github/v29/github" - "golang.org/x/oauth2" -) - -type githubClient struct { - clt *github.Client - owner string - repo string - pr int - author string - commentBody string - authorAssociation string - ctx context.Context -} - -func newGithubClient(ctx context.Context, e *github.IssueCommentEvent) (*githubClient, error) { - ghToken := os.Getenv("GITHUB_TOKEN") - if ghToken == "" { - return nil, fmt.Errorf("env var missing") - } - ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: ghToken}) - tc := oauth2.NewClient(ctx, ts) - return &githubClient{ - clt: github.NewClient(tc), - owner: *e.GetRepo().Owner.Login, - repo: *e.GetRepo().Name, - pr: *e.GetIssue().Number, - author: *e.Sender.Login, - authorAssociation: *e.GetComment().AuthorAssociation, - commentBody: *e.GetComment().Body, - ctx: ctx, - }, nil -} - -func (c githubClient) postComment(commentBody string) error { - issueComment := &github.IssueComment{Body: github.String(commentBody)} - _, _, err := c.clt.Issues.CreateComment(c.ctx, c.owner, c.repo, c.pr, issueComment) - return err -} - -func (c githubClient) createLabel(labelName string) error { - benchmarkLabel := []string{labelName} - _, _, err := c.clt.Issues.AddLabelsToIssue(c.ctx, c.owner, c.repo, c.pr, benchmarkLabel) - return err -} - -func (c githubClient) getLastCommitSHA() (string, error) { - // https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request - listops := &github.ListOptions{Page: 1, PerPage: 250} - l, _, err := c.clt.PullRequests.ListCommits(c.ctx, c.owner, c.repo, c.pr, listops) - if err != nil { - return "", fmt.Errorf("ListCommits(%q,%q,%d): %w", c.owner, c.repo, c.pr, err) - } - if len(l) == 0 { - return "", fmt.Errorf("pr does not have a commit") - } - return l[len(l)-1].GetSHA(), nil -} - -func (c githubClient) createRepositoryDispatch(eventType string, clientPayload map[string]string) error { - allArgs, err := json.Marshal(clientPayload) - if err != nil { - return fmt.Errorf("%w: could not encode client payload", err) - } - cp := json.RawMessage(string(allArgs)) - - rd := github.DispatchRequestOptions{ - EventType: eventType, - ClientPayload: &cp, - } - - log.Printf("creating repository_dispatch with payload: %v", string(allArgs)) - _, _, err = c.clt.Repositories.Dispatch(c.ctx, c.owner, c.repo, rd) - return err -} diff --git a/tools/commentMonitor/main.go b/tools/commentMonitor/main.go deleted file mode 100644 index e90c2310e..000000000 --- a/tools/commentMonitor/main.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2019 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "fmt" - "log" - "net/http" - "os" - "path/filepath" - "strings" - - "github.com/google/go-github/v29/github" - "gopkg.in/alecthomas/kingpin.v2" - "gopkg.in/yaml.v2" -) - -type commentMonitorConfig struct { - configFilePath string - whSecretFilePath string - whSecret []byte - configFile configFile - port string -} - -type commandPrefix struct { - Prefix string `yaml:"prefix"` - HelpTemplate string `yaml:"help_template"` - VerifyUser bool `yaml:"verify_user"` -} - -type webhookEvent struct { - EventType string `yaml:"event_type"` - CommentTemplate string `yaml:"comment_template"` - RegexString string `yaml:"regex_string"` - Label string `yaml:"label"` -} - -type configFile struct { - Prefixes []commandPrefix `yaml:"prefixes"` - WebhookEvents []webhookEvent `yaml:"events"` -} - -func main() { - log.SetFlags(log.Ltime | log.Lshortfile) - cmConfig := commentMonitorConfig{} - - app := kingpin.New(filepath.Base(os.Args[0]), `commentMonitor GithubAction - Post and monitor GitHub comments.`) - app.HelpFlag.Short('h') - app.Flag("webhooksecretfile", "path to webhook secret file"). - Default("./whsecret"). - StringVar(&cmConfig.whSecretFilePath) - app.Flag("config", "Filepath to config file."). - Default("./config.yml"). - StringVar(&cmConfig.configFilePath) - app.Flag("port", "port number to run webhook in."). - Default("8080"). - StringVar(&cmConfig.port) - kingpin.MustParse(app.Parse(os.Args[1:])) - - mux := http.NewServeMux() - mux.HandleFunc("/", cmConfig.webhookExtract) - log.Println("Server is ready to handle requests at", cmConfig.port) - log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", cmConfig.port), mux)) -} - -func (c *commentMonitorConfig) loadConfig() error { - // Get config file. - data, err := os.ReadFile(c.configFilePath) - if err != nil { - return err - } - err = yaml.UnmarshalStrict(data, &c.configFile) - if err != nil { - return fmt.Errorf("cannot unmarshal data: %w", err) - } - if len(c.configFile.WebhookEvents) == 0 || len(c.configFile.Prefixes) == 0 { - return fmt.Errorf("empty eventmap or prefix list") - } - // Get webhook secret. - c.whSecret, err = os.ReadFile(c.whSecretFilePath) - if err != nil { - return err - } - return nil -} - -func extractCommand(s string) string { - s = strings.TrimLeft(s, "\r\n\t ") - if i := strings.Index(s, "\n"); i != -1 { - s = s[:i] - } - s = strings.TrimRight(s, "\r\n\t ") - return s -} - -func (c *commentMonitorConfig) webhookExtract(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - - // Load config on every request. - err := c.loadConfig() - if err != nil { - log.Println(err) - http.Error(w, "comment-monitor configuration incorrect", http.StatusInternalServerError) - return - } - - // Validate payload. - payload, err := github.ValidatePayload(r, c.whSecret) - if err != nil { - log.Println(err) - http.Error(w, "unable to read webhook body", http.StatusBadRequest) - return - } - - // Setup commentMonitor client. - cmClient := commentMonitorClient{ - allArgs: make(map[string]string), - events: c.configFile.WebhookEvents, - prefixes: c.configFile.Prefixes, - } - - // Parse webhook event. - event, err := github.ParseWebHook(github.WebHookType(r), payload) - if err != nil { - log.Println(err) - http.Error(w, "unable to parse webhook", http.StatusBadRequest) - return - } - - switch e := event.(type) { - case *github.IssueCommentEvent: - - if *e.Action != "created" { - http.Error(w, "issue_comment type must be 'created'", http.StatusOK) - return - } - - // Setup github client. - ctx := context.Background() - cmClient.ghClient, err = newGithubClient(ctx, e) - if err != nil { - log.Println(err) - http.Error(w, "could not create GitHub client", http.StatusBadRequest) - return - } - - // Strip whitespace. - command := extractCommand(cmClient.ghClient.commentBody) - - // Command check. - if !cmClient.checkCommandPrefix(command) { - http.Error(w, "comment validation failed", http.StatusOK) - return - } - - // Validate regex. - if !cmClient.validateRegex(command) { - log.Println("invalid command syntax: ", command) - err = cmClient.generateAndPostErrorComment() - if err != nil { - log.Println(err) - http.Error(w, "could not post comment to GitHub", http.StatusBadRequest) - return - } - http.Error(w, "command syntax invalid", http.StatusBadRequest) - return - } - - // Verify user. - err = cmClient.verifyUser() - if err != nil { - log.Println(err) - http.Error(w, "user not allowed to run command", http.StatusForbidden) - return - } - - // Extract args. - err = cmClient.extractArgs(command) - if err != nil { - log.Println(err) - http.Error(w, "could not extract arguments", http.StatusBadRequest) - return - } - - // Post generated comment to GitHub pr. - err = cmClient.generateAndPostSuccessComment() - if err != nil { - log.Println(err) - http.Error(w, "could not post comment to GitHub", http.StatusBadRequest) - return - } - - // Set label to GitHub pr. - err = cmClient.postLabel() - if err != nil { - log.Println(err) - http.Error(w, "could not set label to GitHub", http.StatusBadRequest) - return - } - - default: - log.Println("only issue_comment event is supported") - } -} diff --git a/tools/commentMonitor/main_test.go b/tools/commentMonitor/main_test.go deleted file mode 100644 index f0c17be48..000000000 --- a/tools/commentMonitor/main_test.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2020 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import "testing" - -func TestExtractCommand(t *testing.T) { - testCases := []struct { - commentBody string - command string - }{ - {"/prombench master\r\n", "/prombench master"}, - {"command without forwardslash", "command without forwardslash"}, - } - for _, tc := range testCases { - command := extractCommand(tc.commentBody) - if command != tc.command { - t.Errorf("want %s, got %s", tc.command, command) - } - } -} - -func TestCheckCommandPrefix(t *testing.T) { - cmClient := commentMonitorClient{ - prefixes: []commandPrefix{ - {"/prombench", "help", false}, - {"/somebench", "help", false}, - }, - } - testCases := []struct { - command string - valid bool - }{ - {"/somebench master", true}, - {"/querybench master", false}, - {"prombench master", false}, - } - for _, tc := range testCases { - t.Run(tc.command, func(t *testing.T) { - if cmClient.checkCommandPrefix(tc.command) != tc.valid { - t.Errorf("want %v, got %v", tc.valid, !tc.valid) - } - }) - } -}