diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1d89b7b64..9bf36fd9c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -151,7 +151,7 @@ jobs: set +o pipefail YEAR=$(date +"%Y") - find . -type f -name '*.go' -exec awk 'FNR==1{if ($0!~"Copyright '"${YEAR}"'") print FILENAME ":1:missing copyright or invalid copyright year";}' '{}' + | \ + find . -type f -name '*.go' -exec awk 'FNR==1{if ($0!~"Copyright '"${YEAR}"'" && $0!~"Code generated") print FILENAME ":1:missing copyright or invalid copyright year";}' '{}' + | \ reviewdog -efm="%f:%l:%m" \ -name="copyright-check" \ -reporter="github-pr-check" \ @@ -159,6 +159,13 @@ jobs: -fail-on-error="true" \ -level="error" + - name: generate-check + shell: bash + run: |- + set -eEu + set +o pipefail + make generate-check + - name: tab-check shell: bash env: @@ -167,7 +174,6 @@ jobs: set -eEu set +o pipefail - YEAR=$(date +"%Y") make tabcheck | \ reviewdog -efm="%f:%l:%m" \ -name="tab-check" \ diff --git a/Makefile b/Makefile index 25a548154..51102ea14 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,14 @@ HTML_FILES = $(shell find . -name \*.html) GO_FILES = $(shell find . -name \*.go) MD_FILES = $(shell find . -name \*.md) +generate: + @go generate ./... +.PHONY: generate + +generate-check: generate + @git update-index --refresh && git diff-index --quiet HEAD -- +.PHONY: generate-check + # lint uses the same linter as CI and tries to report the same results running # locally. There is a chance that CI detects linter errors that are not found # locally, but it should be rare. diff --git a/builders/build.yaml b/builders/build.yaml index ac0e43b0b..1700c3486 100644 --- a/builders/build.yaml +++ b/builders/build.yaml @@ -438,6 +438,44 @@ steps: waitFor: - 'push-migrate' +# +# metrics-registrar +# +- id: 'dockerize-metrics-registrar' + name: 'docker:19' + args: + - 'build' + - '--file=builders/metrics-registrar.dockerfile' + - '--tag=gcr.io/${PROJECT_ID}/${_REPO}/metrics-registrar:${_TAG}' + - '.' + waitFor: + - 'build' + +- id: 'push-metrics-registrar' + name: 'docker:19' + args: + - 'push' + - 'gcr.io/${PROJECT_ID}/${_REPO}/metrics-registrar:${_TAG}' + waitFor: + - 'dockerize-metrics-registrar' + +- id: 'attest-metrics-registrar' + name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:335.0.0' + args: + - 'bash' + - '-eEuo' + - 'pipefail' + - '-c' + - |- + ARTIFACT_URL=$(docker inspect gcr.io/${PROJECT_ID}/${_REPO}/metrics-registrar:${_TAG} --format='{{index .RepoDigests 0}}') + gcloud beta container binauthz attestations sign-and-create \ + --project "${PROJECT_ID}" \ + --artifact-url "$${ARTIFACT_URL}" \ + --attestor "${_BINAUTHZ_ATTESTOR}" \ + --keyversion "${_BINAUTHZ_KEY_VERSION}" + waitFor: + - 'push-metrics-registrar' + # # modeler diff --git a/builders/deploy.yaml b/builders/deploy.yaml index 8f19e49fa..03b90c783 100644 --- a/builders/deploy.yaml +++ b/builders/deploy.yaml @@ -169,6 +169,29 @@ steps: waitFor: - '-' + +# +# metrics-registrar +# +- id: 'deploy-metrics-registrar' + name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:335.0.0-alpine' + args: + - 'bash' + - '-eEuo' + - 'pipefail' + - '-c' + - |- + gcloud run deploy "metrics-registrar" \ + --quiet \ + --project "${PROJECT_ID}" \ + --platform "managed" \ + --region "${_REGION}" \ + --image "gcr.io/${PROJECT_ID}/${_REPO}/metrics-registrar:${_TAG}" \ + --no-traffic + waitFor: + - '-' + + # # modeler # diff --git a/builders/promote.yaml b/builders/promote.yaml index 98dec52de..f99f18edf 100644 --- a/builders/promote.yaml +++ b/builders/promote.yaml @@ -182,6 +182,26 @@ steps: waitFor: - '-' +# +# metrics-registrar +# +- id: 'promote-metrics-registrar' + name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:335.0.0-alpine' + args: + - 'bash' + - '-eEuo' + - 'pipefail' + - '-c' + - |- + gcloud run services update-traffic "metrics-registrar" \ + --quiet \ + --project "${PROJECT_ID}" \ + --platform "managed" \ + --region "${_REGION}" \ + --to-revisions "${_REVISION}=${_PERCENTAGE}" + waitFor: + - '-' + # # rotation # diff --git a/cmd/metrics-registrar/main.go b/cmd/metrics-registrar/main.go new file mode 100644 index 000000000..15d48dd16 --- /dev/null +++ b/cmd/metrics-registrar/main.go @@ -0,0 +1,120 @@ +// Copyright 2021 the Exposure Notifications Verification Server 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. + +// This server registers metrics for Stackdriver. +package main + +import ( + "context" + "fmt" + "net/http" + "os/signal" + "syscall" + + "github.com/google/exposure-notifications-verification-server/internal/buildinfo" + "github.com/google/exposure-notifications-verification-server/pkg/config" + "github.com/google/exposure-notifications-verification-server/pkg/controller/metricsregistrar" + "github.com/google/exposure-notifications-verification-server/pkg/controller/middleware" + "github.com/google/exposure-notifications-verification-server/pkg/render" + + "github.com/google/exposure-notifications-server/pkg/logging" + "github.com/google/exposure-notifications-server/pkg/observability" + "github.com/google/exposure-notifications-server/pkg/server" + + "github.com/gorilla/mux" +) + +func main() { + ctx, done := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + + logger := logging.NewLoggerFromEnv(). + With("build_id", buildinfo.BuildID). + With("build_tag", buildinfo.BuildTag) + ctx = logging.WithLogger(ctx, logger) + + defer func() { + done() + if r := recover(); r != nil { + logger.Fatalw("application panic", "panic", r) + } + }() + + err := realMain(ctx) + done() + + if err != nil { + logger.Fatal(err) + } + logger.Info("successful shutdown") +} + +func realMain(ctx context.Context) error { + logger := logging.FromContext(ctx) + + cfg, err := config.NewMetricsRegistrarConfig(ctx) + if err != nil { + return fmt.Errorf("failed to process config: %w", err) + } + + // Setup monitoring + logger.Info("configuring observability exporter") + oeConfig := cfg.ObservabilityExporterConfig() + oe, err := observability.NewFromEnv(oeConfig) + if err != nil { + return fmt.Errorf("unable to create ObservabilityExporter provider: %w", err) + } + if err := oe.StartExporter(ctx); err != nil { + return fmt.Errorf("error initializing observability exporter: %w", err) + } + defer oe.Close() + ctx, obs := middleware.WithObservability(ctx) + logger.Infow("observability exporter", "config", oeConfig) + + // Create the renderer + h, err := render.New(ctx, nil, cfg.DevMode) + if err != nil { + return fmt.Errorf("failed to create renderer: %w", err) + } + + // Create the router + r := mux.NewRouter() + + // Common observability context + r.Use(obs) + + // Request ID injection + populateRequestID := middleware.PopulateRequestID(h) + r.Use(populateRequestID) + + // Logger injection + populateLogger := middleware.PopulateLogger(logger) + r.Use(populateLogger) + + // Recovery injection + recovery := middleware.Recovery(h) + r.Use(recovery) + + metricsRegistrarController := metricsregistrar.New(cfg, h) + if err := metricsRegistrarController.CreateMetrics(ctx); err != nil { + return fmt.Errorf("failed to create metrics: %w", err) + } + r.Handle("/", metricsRegistrarController.HandleRoot()).Methods(http.MethodGet) + + srv, err := server.New(cfg.Port) + if err != nil { + return fmt.Errorf("failed to create server: %w", err) + } + logger.Infow("server listening", "port", cfg.Port) + return srv.ServeHTTPHandler(ctx, r) +} diff --git a/go.mod b/go.mod index f38758bc8..1b0f4c8e0 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,18 @@ module github.com/google/exposure-notifications-verification-server go 1.16 require ( - cloud.google.com/go v0.91.1 + cloud.google.com/go v0.93.3 // indirect cloud.google.com/go/firestore v1.5.0 // indirect + cloud.google.com/go/kms v0.1.0 // indirect + cloud.google.com/go/monitoring v0.1.0 + cloud.google.com/go/secretmanager v0.1.0 + cloud.google.com/go/trace v0.1.0 // indirect contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200615190824-f8c219d2d895 // indirect contrib.go.opencensus.io/integrations/ocsql v0.1.7 firebase.google.com/go v3.13.0+incompatible github.com/Azure/azure-sdk-for-go v56.2.0+incompatible // indirect github.com/NYTimes/gziphandler v1.1.1 - github.com/aws/aws-sdk-go v1.40.22 // indirect + github.com/aws/aws-sdk-go v1.40.24 // indirect github.com/chromedp/cdproto v0.0.0-20210808225517-c36c1bd4c35e github.com/chromedp/chromedp v0.7.4 github.com/dustin/go-humanize v1.0.0 @@ -25,7 +29,7 @@ require ( github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 // indirect github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9 // indirect github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 - github.com/google/exposure-notifications-server v0.35.0 + github.com/google/exposure-notifications-server v0.35.1-0.20210818171456-e90a92bf7dd0 github.com/google/go-cmp v0.5.6 github.com/google/uuid v1.3.0 github.com/gorilla/handlers v1.5.1 @@ -48,7 +52,7 @@ require ( github.com/opencensus-integrations/redigo v2.0.1+incompatible github.com/ory/dockertest v3.3.5+incompatible github.com/prometheus/common v0.30.0 // indirect - github.com/prometheus/procfs v0.7.2 // indirect + github.com/prometheus/procfs v0.7.3 // indirect github.com/rakutentech/jwk-go v1.0.1 github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 @@ -61,12 +65,12 @@ require ( github.com/unrolled/secure v1.0.9 go.opencensus.io v0.23.0 go.uber.org/zap v1.19.0 - golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e // indirect + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect golang.org/x/mod v0.5.0 // indirect golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d - golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 // indirect + golang.org/x/oauth2 v0.0.0-20210817223510-7df4dd6e12ab // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71 // indirect + golang.org/x/sys v0.0.0-20210818153620-00dd8d7831e7 // indirect golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect golang.org/x/tools v0.1.5 diff --git a/go.sum b/go.sum index 94fc939f5..8a42a487a 100644 --- a/go.sum +++ b/go.sum @@ -27,10 +27,11 @@ cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.91.1 h1:w+u8ttN/QtYrpvgXNUd2G6kwqrqCIQbkINlXQjHP1ek= -cloud.google.com/go v0.91.1/go.mod h1:V358WZfbFQkmC3gv5XCxzZq2e3h7OGvQR0IXtj77ylI= +cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.93.3 h1:wPBktZFzYBcCZVARvwVKqH1uEj+aLXofJEtrb4oOsio= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -41,10 +42,16 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7 cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.5.0 h1:4qNItsmc4GP6UOZPGemmHY4ZfPofVhcaKXsYw9wm9oA= cloud.google.com/go/firestore v1.5.0/go.mod h1:c4nNYR1qdq7eaZ+jSc5fonrQN2k3M7sWATcYTiakjEo= +cloud.google.com/go/kms v0.1.0 h1:VXAb5OzejDcyhFzIDeZ5n5AUdlsFnCyexuascIwWMj0= +cloud.google.com/go/kms v0.1.0/go.mod h1:8Qp8PCAypHg4FdmlyW1QRAv09BGQ9Uzh7JnmIZxPk+c= +cloud.google.com/go/monitoring v0.1.0 h1:vssDZ792skH6AWCDH1OogKfs/FzgEVTB/yUAzfgBR24= +cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/secretmanager v0.1.0 h1:ovHBlQ62xZxSmnf4RarqU45rSYl+QB/FkzZGvE/FjWI= +cloud.google.com/go/secretmanager v0.1.0/go.mod h1:3nGKHvnzDUVit7U0S9KAKJ4aOsO1xtwRG+7ey5LK1bM= cloud.google.com/go/spanner v1.9.0/go.mod h1:xvlEn0NZ5v1iJPYsBnUVRDNvccDxsBTEi16pJRKQVws= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= @@ -53,6 +60,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.16.0 h1:1UwAux2OZP4310YXg5ohqBEpV16Y93uZG4+qOX7K2Kg= cloud.google.com/go/storage v1.16.0/go.mod h1:ieKBmUyzcftN5tbxwnXClMKH00CfcQ+xL6NN0r5QfmE= +cloud.google.com/go/trace v0.1.0 h1:nUGUK79FOkN0UGUXhBmVBkbu1PYsHe0YyFSPLOD9Npg= +cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g= contrib.go.opencensus.io/exporter/ocagent v0.7.0/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200615190824-f8c219d2d895 h1:bXMXgHq+WAIkI2dQivk1yMyKVVqMj8emLmhEqQghPWw= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200615190824-f8c219d2d895/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= @@ -149,8 +158,8 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.40.2/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.40.22 h1:iit4tJ1hjL2GlNCrbE4aJza6jTmvEE2pDTnShct/yyY= -github.com/aws/aws-sdk-go v1.40.22/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.40.24 h1:qtXDYFzAxEmmZaa+4JA9loBqOujO0vm4ZOJoEmjG21E= +github.com/aws/aws-sdk-go v1.40.24/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= @@ -410,8 +419,8 @@ github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 h1:V2IgdyerlBa/MxaEFR github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= 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/exposure-notifications-server v0.35.0 h1:Q6VS6wFG3sdk3jS1Ie1lr5gJ5OQjORF0ZXnZKfkUoa4= -github.com/google/exposure-notifications-server v0.35.0/go.mod h1:pRCNPtvty7GiaOaePC2xBwWeRSgZ7EcSVmuhL70BCEQ= +github.com/google/exposure-notifications-server v0.35.1-0.20210818171456-e90a92bf7dd0 h1:/p+Ofe2XLQygdmIzBg6u1V/Rv/dIEIbHa3gYa+eaMtA= +github.com/google/exposure-notifications-server v0.35.1-0.20210818171456-e90a92bf7dd0/go.mod h1:pRCNPtvty7GiaOaePC2xBwWeRSgZ7EcSVmuhL70BCEQ= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -449,9 +458,7 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210804190019-f964ff605595/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -658,7 +665,6 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -887,8 +893,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.2 h1:zE6zJjRS9S916ptrZ326OU0++1XRwHgxkvCFflxx6Fo= -github.com/prometheus/procfs v0.7.2/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/statsd_exporter v0.20.0/go.mod h1:YL3FWCG8JBBtaUSxAg4Gz2ZYu22bS84XM89ZQXXTWmQ= github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8= github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= @@ -1072,8 +1078,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e h1:VvfwVmMH40bpMeizC9/K7ipM5Qjucuu16RWfneFPyhQ= -golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 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= @@ -1191,8 +1197,8 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 h1:Ati8dO7+U7mxpkPSxBZQEvzHVUYB/MqCklCN8ig5w/o= -golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210817223510-7df4dd6e12ab h1:llrcWN/wOwO+6gAyfBzxb5hZ+c3mriU/0+KNgYu6adA= +golang.org/x/oauth2 v0.0.0-20210817223510-7df4dd6e12ab/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1289,8 +1295,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71 h1:ikCpsnYR+Ew0vu99XlDp55lGgDJdIMx3f4a18jfse/s= -golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210818153620-00dd8d7831e7 h1:/bmDWM82ZX7TawqxuI8kVjKI0TXHdSY6pHJArewwHtU= +golang.org/x/sys v0.0.0-20210818153620-00dd8d7831e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1421,7 +1427,6 @@ google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtuk google.golang.org/api v0.49.0/go.mod h1:BECiH72wsfwUvOVn3+btPD5WHi0LzavZReBndi42L18= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.52.0/go.mod h1:Him/adpjt0sxtkWViy0b6xyKW/SD71CwdJ7HqJo7SrU= google.golang.org/api v0.54.0 h1:ECJUVngj71QI6XEm7b1sAf8BljU5inEhMbKPR8Lxhhk= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -1495,11 +1500,9 @@ google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+n google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210811021853-ddbe55d93216/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210816143620-e15ff196659d h1:fPtHPeysWvGVJwQFKu3B7H2DB2sOEsW7UTayKkWESKw= google.golang.org/genproto v0.0.0-20210816143620-e15ff196659d/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= diff --git a/pkg/config/metrics_registrar_config.go b/pkg/config/metrics_registrar_config.go new file mode 100644 index 000000000..077e22033 --- /dev/null +++ b/pkg/config/metrics_registrar_config.go @@ -0,0 +1,56 @@ +// Copyright 2021 the Exposure Notifications Verification Server 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 config + +import ( + "context" + + "github.com/google/exposure-notifications-server/pkg/observability" + + "github.com/sethvargo/go-envconfig" +) + +// MetricsRegistrarConfig represents the environment based configuration for the +// metrics registration server. +type MetricsRegistrarConfig struct { + Observability observability.Config + Features FeatureConfig + + // DevMode produces additional debugging information. Do not enable in + // production environments. + DevMode bool `env:"DEV_MODE"` + + // Port is the port on which to bind. + Port string `env:"PORT,default=8080"` +} + +// NewMetricsRegistrarConfig returns the environment config for the metrics +// registration server. Only needs to be called once per instance, but may be +// called multiple times. +func NewMetricsRegistrarConfig(ctx context.Context) (*MetricsRegistrarConfig, error) { + var config MetricsRegistrarConfig + if err := ProcessWith(ctx, &config, envconfig.OsLookuper()); err != nil { + return nil, err + } + return &config, nil +} + +func (c *MetricsRegistrarConfig) Validate() error { + return nil +} + +func (c *MetricsRegistrarConfig) ObservabilityExporterConfig() *observability.Config { + return &c.Observability +} diff --git a/pkg/controller/metricsregistrar/all_metrics.go b/pkg/controller/metricsregistrar/all_metrics.go new file mode 100644 index 000000000..184438602 --- /dev/null +++ b/pkg/controller/metricsregistrar/all_metrics.go @@ -0,0 +1,20 @@ +// Code generated by gen-metrics-registrar. DO NOT EDIT. +package metricsregistrar + +import ( + _ "github.com/google/exposure-notifications-verification-server/internal/clients" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/appsync" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/backup" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/certapi" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/cleanup" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/e2erunner" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/issueapi" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/modeler" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/rotation" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/statspuller" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/user" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/userreport" + _ "github.com/google/exposure-notifications-verification-server/pkg/controller/verifyapi" + _ "github.com/google/exposure-notifications-verification-server/pkg/database" + _ "github.com/google/exposure-notifications-verification-server/pkg/ratelimit/limitware" +) diff --git a/pkg/controller/metricsregistrar/create_metrics.go b/pkg/controller/metricsregistrar/create_metrics.go new file mode 100644 index 000000000..32eeb38cc --- /dev/null +++ b/pkg/controller/metricsregistrar/create_metrics.go @@ -0,0 +1,115 @@ +// Copyright 2021 the Exposure Notifications Verification Server 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 metricsregistrar + +import ( + "context" + "fmt" + "runtime" + "time" + + monitoring "cloud.google.com/go/monitoring/apiv3/v2" + "github.com/google/exposure-notifications-server/pkg/logging" + "github.com/google/exposure-notifications-server/pkg/observability" + "github.com/hashicorp/go-multierror" + "golang.org/x/sync/semaphore" + monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3" +) + +// CreateMetrics creates the upstream metrics in Stackdriver. +func (c *Controller) CreateMetrics(ctx context.Context) error { + logger := logging.FromContext(ctx) + + logger.Infow("starting metric registration") + defer logger.Infow("finished metric registration") + + // Extract the project ID. + sd := c.config.Observability.Stackdriver + if sd == nil { + return fmt.Errorf("observability export is not stackdriver") + } + projectID := sd.ProjectID + + // Create the metrics client. + client, err := monitoring.NewMetricClient(context.Background()) + if err != nil { + return fmt.Errorf("failed to create metrics client: %w", err) + } + + // Create the Stackdriver exporter. + exporter, err := observability.NewStackdriver(context.Background(), &observability.StackdriverConfig{ + ProjectID: projectID, + }) + if err != nil { + return fmt.Errorf("failed to create Stackdriver exporter: %w", err) + } + + // Register metric descriptors with Stackdriver. + allViews := observability.AllViews() + + workers := int64(runtime.NumCPU()) + if workers < 3 { + workers = 3 + } + + sem := semaphore.NewWeighted(workers) + errCh := make(chan error, len(allViews)) + + for _, view := range allViews { + view := view + + if err := sem.Acquire(ctx, 1); err != nil { + return fmt.Errorf("failed to acquire semaphore: %w", err) + } + + logger.Infow("registering metrics exporter", "view", view.Name) + + go func() { + defer sem.Release(1) + + metricDescriptor, err := exporter.ViewToMetricDescriptor(view) + if err != nil { + errCh <- fmt.Errorf("failed to convert view %s to MetricDescriptor: %w", view.Name, err) + return + } + + req := &monitoringpb.CreateMetricDescriptorRequest{ + Name: "projects/" + projectID, + MetricDescriptor: metricDescriptor, + } + + ctx, done := context.WithTimeout(ctx, 10*time.Second) + defer done() + + if _, err := client.CreateMetricDescriptor(ctx, req); err != nil { + errCh <- fmt.Errorf("failed to create metric descriptor for view %s: %w", view.Name, err) + return + } + }() + } + + if err := sem.Acquire(ctx, workers); err != nil { + return fmt.Errorf("failed to wait for semaphore: %w", err) + } + close(errCh) + + var merr *multierror.Error + for err := range errCh { + if err != nil { + merr = multierror.Append(merr, err) + } + } + return merr.ErrorOrNil() +} diff --git a/pkg/controller/metricsregistrar/handle_root.go b/pkg/controller/metricsregistrar/handle_root.go new file mode 100644 index 000000000..42c9f358c --- /dev/null +++ b/pkg/controller/metricsregistrar/handle_root.go @@ -0,0 +1,25 @@ +// Copyright 2021 the Exposure Notifications Verification Server 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 metricsregistrar + +import ( + "net/http" +) + +func (c *Controller) HandleRoot() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c.h.RenderJSON(w, http.StatusOK, nil) + }) +} diff --git a/pkg/controller/metricsregistrar/metricsregistrar.go b/pkg/controller/metricsregistrar/metricsregistrar.go new file mode 100644 index 000000000..cec227900 --- /dev/null +++ b/pkg/controller/metricsregistrar/metricsregistrar.go @@ -0,0 +1,37 @@ +// Copyright 2021 the Exposure Notifications Verification Server authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:generate go run github.com/google/exposure-notifications-server/tools/gen-metrics-registrar -module-name=github.com/google/exposure-notifications-verification-server -module-root=../../.. -pkg=metricsregistrar -dest=./all_metrics.go + +// Package metricsregistrar implements metrics registration on load. +package metricsregistrar + +import ( + "github.com/google/exposure-notifications-verification-server/pkg/config" + "github.com/google/exposure-notifications-verification-server/pkg/render" +) + +// Controller is a controller for the metrics registration service. +type Controller struct { + config *config.MetricsRegistrarConfig + h *render.Renderer +} + +// New creates a new controller. +func New(cfg *config.MetricsRegistrarConfig, h *render.Renderer) *Controller { + return &Controller{ + config: cfg, + h: h, + } +} diff --git a/terraform/service_metrics_registrar.tf b/terraform/service_metrics_registrar.tf new file mode 100644 index 000000000..429bd3073 --- /dev/null +++ b/terraform/service_metrics_registrar.tf @@ -0,0 +1,121 @@ +# Copyright 2021 the Exposure Notifications Verification Server 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. + +resource "google_service_account" "metrics-registrar" { + project = var.project + account_id = "en-ver-metrics-registrar-sa" + display_name = "Verification Metrics Registrar" +} + +resource "google_service_account_iam_member" "cloudbuild-deploy-metrics-registrar" { + service_account_id = google_service_account.metrics-registrar.id + role = "roles/iam.serviceAccountUser" + member = "serviceAccount:${local.cloudbuild_email}" +} + +resource "google_project_iam_member" "metrics-registrar-observability" { + for_each = local.observability_iam_roles + project = var.project + role = each.key + member = "serviceAccount:${google_service_account.metrics-registrar.email}" +} + +resource "google_cloud_run_service" "metrics-registrar" { + name = "metrics-registrar" + location = var.region + + autogenerate_revision_name = true + + metadata { + annotations = merge( + local.default_service_annotations, + var.default_service_annotations_overrides, + lookup(var.service_annotations, "metrics-registrar", {}) + ) + } + + template { + spec { + service_account_name = google_service_account.metrics-registrar.email + + containers { + image = "gcr.io/${var.project}/github.com/google/exposure-notifications-verification-server/metrics-registrar:initial" + + resources { + limits = { + cpu = "1000m" + memory = "1G" + } + } + + + dynamic "env" { + for_each = merge( + local.gcp_config, + local.observability_config, + + // This MUST come last to allow overrides! + lookup(var.service_environment, "_all", {}), + lookup(var.service_environment, "metrics-registrar", {}), + ) + + content { + name = env.key + value = env.value + } + } + } + } + + metadata { + annotations = merge( + local.default_revision_annotations, + var.default_revision_annotations_overrides, + { "autoscaling.knative.dev/maxScale" = "1" }, + lookup(var.revision_annotations, "metrics-registrar", {}) + ) + } + } + + depends_on = [ + google_project_service.services["run.googleapis.com"], + + google_project_iam_member.metrics-registrar-observability, + + null_resource.build, + null_resource.migrate, + ] + + lifecycle { + ignore_changes = [ + metadata[0].annotations["client.knative.dev/user-image"], + metadata[0].annotations["run.googleapis.com/client-name"], + metadata[0].annotations["run.googleapis.com/client-version"], + metadata[0].annotations["run.googleapis.com/ingress-status"], + metadata[0].annotations["serving.knative.dev/creator"], + metadata[0].annotations["serving.knative.dev/lastModifier"], + metadata[0].labels["cloud.googleapis.com/location"], + template[0].metadata[0].annotations["client.knative.dev/user-image"], + template[0].metadata[0].annotations["run.googleapis.com/client-name"], + template[0].metadata[0].annotations["run.googleapis.com/client-version"], + template[0].metadata[0].annotations["serving.knative.dev/creator"], + template[0].metadata[0].annotations["serving.knative.dev/lastModifier"], + template[0].spec[0].containers[0].image, + ] + } +} + +output "metrics-registrar_url" { + value = google_cloud_run_service.metrics-registrar.status.0.url +} diff --git a/tools/tools.go b/tools/tools.go index a3bb89189..3eaeeba17 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -18,6 +18,7 @@ package tools import ( + _ "github.com/google/exposure-notifications-server/tools/gen-metrics-registrar" _ "github.com/sethvargo/zapw/cmd/zapw" _ "golang.org/x/tools/cmd/goimports" )