mirror of
https://github.com/distribution/distribution.git
synced 2026-10-28 10:15:27 +08:00
chore(deps): Bump Go to latest 1.25 in CI workflows and go.mod
In prep for release + fixing sec vulns * https://github.com/distribution/distribution/security/dependabot/22 * https://github.com/distribution/distribution/security/dependabot/23 otel is particularly silly, especially the contrib deps. Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
This commit is contained in:
1449 files changed
+131017
-69590
No files matched your search
@@ -33,8 +33,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go:
|
||||
- 1.24.x
|
||||
- 1.25.7
|
||||
- 1.25.x
|
||||
- 1.26.1
|
||||
target:
|
||||
- test-coverage
|
||||
- test-s3-storage
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
# GO_VERSION sets the version of the golang base image to use.
|
||||
# It must be a supported tag in the docker.io/library/golang image repository.
|
||||
ARG GO_VERSION=1.25.7
|
||||
ARG GO_VERSION=1.25.8
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# GO_VERSION sets the version of the golang base image to use.
|
||||
# It must be a supported tag in the docker.io/library/golang image repository.
|
||||
ARG GO_VERSION=1.25.7
|
||||
ARG GO_VERSION=1.25.8
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# GO_VERSION sets the version of the golang base image to use.
|
||||
# It must be a supported tag in the docker.io/library/golang image repository.
|
||||
ARG GO_VERSION=1.25.7
|
||||
ARG GO_VERSION=1.25.8
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# GO_VERSION sets the version of the golang base image to use.
|
||||
# It must be a supported tag in the docker.io/library/golang image repository.
|
||||
ARG GO_VERSION=1.25.7
|
||||
ARG GO_VERSION=1.25.8
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
@@ -27,4 +27,4 @@ RUN --mount=type=bind,target=. \
|
||||
--mount=type=cache,target=/root/.cache \
|
||||
--mount=from=golangci-lint,source=/usr/bin/golangci-lint,target=/usr/bin/golangci-lint \
|
||||
golangci-lint config verify && \
|
||||
golangci-lint --timeout "${TIMEOUT}" --build-tags "${BUILDTAGS}" run
|
||||
golangci-lint --timeout "${TIMEOUT}" --build-tags "${BUILDTAGS}" run
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# GO_VERSION sets the version of the golang base image to use.
|
||||
# It must be a supported tag in the docker.io/library/golang image repository.
|
||||
ARG GO_VERSION=1.25.7
|
||||
ARG GO_VERSION=1.25.8
|
||||
|
||||
# ALPINE_VERSION sets the version of the alpine base image to use, including for the golang image.
|
||||
# It must be a supported tag in the docker.io/library/alpine image repository
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
module github.com/distribution/distribution/v3
|
||||
|
||||
go 1.24.0
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
cloud.google.com/go/storage v1.45.0
|
||||
cloud.google.com/go/storage v1.50.0
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
|
||||
@@ -28,53 +28,52 @@ require (
|
||||
github.com/redis/go-redis/v9 v9.7.3
|
||||
github.com/sirupsen/logrus v1.9.4
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0
|
||||
go.opentelemetry.io/otel v1.32.0
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0
|
||||
go.opentelemetry.io/otel/sdk v1.32.0
|
||||
go.opentelemetry.io/otel/trace v1.32.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0
|
||||
go.opentelemetry.io/otel v1.42.0
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0
|
||||
go.opentelemetry.io/otel/sdk v1.42.0
|
||||
go.opentelemetry.io/otel/trace v1.42.0
|
||||
golang.org/x/crypto v0.48.0
|
||||
golang.org/x/net v0.50.0
|
||||
golang.org/x/net v0.51.0
|
||||
golang.org/x/oauth2 v0.35.0
|
||||
golang.org/x/sync v0.19.0
|
||||
google.golang.org/api v0.197.0
|
||||
google.golang.org/api v0.214.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.16.1 // indirect
|
||||
cloud.google.com/go v0.115.1 // indirect
|
||||
cloud.google.com/go/auth v0.9.3 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.5.1 // indirect
|
||||
cloud.google.com/go/iam v1.2.1 // indirect
|
||||
cloud.google.com/go/monitoring v1.21.0 // indirect
|
||||
cel.dev/expr v0.25.1 // indirect
|
||||
cloud.google.com/go v0.116.0 // indirect
|
||||
cloud.google.com/go/auth v0.13.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
cloud.google.com/go/iam v1.2.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.21.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.13.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/s2a-go v0.1.8 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
@@ -82,40 +81,43 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.60.1 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
||||
github.com/prometheus/procfs v0.20.1 // indirect
|
||||
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.29.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.54.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.18.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.42.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.18.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.42.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
google.golang.org/grpc v1.68.0 // indirect
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/grpc v1.79.3 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -1,26 +1,26 @@
|
||||
cel.dev/expr v0.16.1 h1:NR0+oFYzR1CqLFhTAqg3ql59G9VfN8fKq1TCHJ6gq1g=
|
||||
cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
|
||||
cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4=
|
||||
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
|
||||
cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
|
||||
cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U=
|
||||
cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
|
||||
cloud.google.com/go/compute/metadata v0.5.1 h1:NM6oZeZNlYjiwYje+sYFjEpP0Q0zCan1bmQW/KmIrGs=
|
||||
cloud.google.com/go/compute/metadata v0.5.1/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
|
||||
cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU=
|
||||
cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g=
|
||||
cloud.google.com/go/logging v1.11.0 h1:v3ktVzXMV7CwHq1MBF65wcqLMA7i+z3YxbUsoK7mOKs=
|
||||
cloud.google.com/go/logging v1.11.0/go.mod h1:5LDiJC/RxTt+fHc1LAt20R9TKiUTReDg6RuuFOZ67+A=
|
||||
cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc=
|
||||
cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0=
|
||||
cloud.google.com/go/monitoring v1.21.0 h1:EMc0tB+d3lUewT2NzKC/hr8cSR9WsUieVywzIHetGro=
|
||||
cloud.google.com/go/monitoring v1.21.0/go.mod h1:tuJ+KNDdJbetSsbSGTqnaBvbauS5kr3Q/koy3Up6r+4=
|
||||
cloud.google.com/go/storage v1.45.0 h1:5av0QcIVj77t+44mV4gffFC/LscFRUhto6UBMB5SimM=
|
||||
cloud.google.com/go/storage v1.45.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE=
|
||||
cloud.google.com/go/trace v1.11.0 h1:UHX6cOJm45Zw/KIbqHe4kII8PupLt/V5tscZUkeiJVI=
|
||||
cloud.google.com/go/trace v1.11.0/go.mod h1:Aiemdi52635dBR7o3zuc9lLjXo3BwGaChEjCa3tJNmM=
|
||||
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
|
||||
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
|
||||
cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs=
|
||||
cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA=
|
||||
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
|
||||
cloud.google.com/go/logging v1.12.0 h1:ex1igYcGFd4S/RZWOCU51StlIEuey5bjqwH9ZYjHibk=
|
||||
cloud.google.com/go/logging v1.12.0/go.mod h1:wwYBt5HlYP1InnrtYI0wtwttpVU1rifnMT7RejksUAM=
|
||||
cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc=
|
||||
cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI=
|
||||
cloud.google.com/go/monitoring v1.21.2 h1:FChwVtClH19E7pJ+e0xUhJPGksctZNVOk2UhMmblmdU=
|
||||
cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU=
|
||||
cloud.google.com/go/storage v1.50.0 h1:3TbVkzTooBvnZsk7WaAQfOsNrdoM8QHusXA1cpk6QJs=
|
||||
cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY=
|
||||
cloud.google.com/go/trace v1.11.2 h1:4ZmaBdL8Ng/ajrgKqY5jfvzqMXbrDcBsUGXOT9aqTtI=
|
||||
cloud.google.com/go/trace v1.11.2/go.mod h1:bn7OwXd4pd5rFuAnTrzBuoZ4ax2XQeG3qNgYmfCy0Io=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8 h1:d+pBUmsteW5tM87xmVXHZ4+LibHRFn40SPAoZJOg2ak=
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
|
||||
@@ -40,8 +40,8 @@ github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mo
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 h1:pB2F2JKCj1Znmp2rwxxt1J0Fg0wezTMgWYk5Mpbi1kg=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1/go.mod h1:itPGVDKf9cC/ov4MdvJ2QZ0khw4bfoo9jzwTJlaxy2k=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 h1:sBEjpZlNHzK1voKq9695PJSX2o5NEXl7/OL3coiIY0c=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1 h1:oTX4vsorBZo/Zdum6OKPA4o7544hm6smoRv1QjpTwGo=
|
||||
@@ -64,18 +64,16 @@ github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdb
|
||||
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w=
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
|
||||
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.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
@@ -84,8 +82,9 @@ github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxG
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
@@ -99,11 +98,15 @@ github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHz
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.13.0 h1:HzkeUz1Knt+3bK+8LG1bxOO/jzWZmdxpwC51i202les=
|
||||
github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||
@@ -112,15 +115,15 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
@@ -144,8 +147,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
|
||||
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||
@@ -156,14 +159,14 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
|
||||
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
|
||||
github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o=
|
||||
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
|
||||
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||
@@ -211,27 +214,30 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
|
||||
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
|
||||
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
||||
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||
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/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
|
||||
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
|
||||
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
|
||||
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
|
||||
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
|
||||
@@ -239,8 +245,8 @@ github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnA
|
||||
github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
|
||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
@@ -251,6 +257,8 @@ github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiT
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -261,60 +269,66 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
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/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w=
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.29.0 h1:TiaiXB4DpGD3sdzNlYQxruQngn5Apwzi1X0DRhuGvDQ=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0 h1:dkBzNEAIKADEaFnuESzcXvpd09vxvDZsOjx11gjUqLk=
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.67.0/go.mod h1:Z5RIwRkZgauOIfnG5IpidvLpERjhTninpP1dTG2jTl4=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0 h1:4fnRcNpc6YFtG3zsFw9achKn3XgmxPxuMuqIL5rE8e8=
|
||||
go.opentelemetry.io/contrib/exporters/autoexport v0.67.0/go.mod h1:qTvIHMFKoxW7HXg02gm6/Wofhq5p3Ib/A/NNt1EoBSQ=
|
||||
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.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94=
|
||||
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s=
|
||||
go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
|
||||
go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
|
||||
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
|
||||
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
|
||||
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 h1:OyrsyzuttWTSur2qN/Lm0m2a8yqyIjUVBZcxFPuXq2o=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0/go.mod h1:C2NGBr+kAB4bk3xtMXfZ94gqFDtg/GkI7e9zqGh5Beg=
|
||||
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0 h1:icqq3Z34UrEFk2u+HMhTtRsvo7Ues+eiJVjaJt62njs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.18.0/go.mod h1:W2m8P+d5Wn5kipj4/xmbt9uMqezEKfBjzVJadfABSBE=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0 h1:H7O6RlGOMTizyl3R08Kn5pdM06bnH8oscSj7o11tmLA=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.42.0/go.mod h1:mBFWu/WOVDkWWsR7Tx7h6EpQB8wsv7P0Yrh0Pb7othc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0 h1:uLXP+3mghfMf7XmV4PkGfFhFKuNWoCvvx5wP/wOXo0o=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.42.0/go.mod h1:v0Tj04armyT59mnURNUJf7RCKcKzq+lgJs6QSjHjaTc=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.64.0 h1:g0LRDXMX/G1SEZtK8zl8Chm4K6GBwRkjPKE36LxiTYs=
|
||||
go.opentelemetry.io/otel/exporters/prometheus v0.64.0/go.mod h1:UrgcjnarfdlBDP3GjDIJWe6HTprwSazNjwsI+Ru6hro=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0 h1:KJVjPD3rcPb98rIs3HznyJlrfx9ge5oJvxxlGR+P/7s=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.18.0/go.mod h1:K3kRa2ckmHWQaTWQdPRHc7qGXASuVuoEQXzrvlA98Ws=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0 h1:lSZHgNHfbmQTPfuTmWVkEu8J8qXaQwuV30pjCcAUvP8=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.42.0/go.mod h1:so9ounLcuoRDu033MW/E0AD4hhUjVqswrMF5FoZlBcw=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs=
|
||||
go.opentelemetry.io/otel/log v0.18.0 h1:XgeQIIBjZZrliksMEbcwMZefoOSMI1hdjiLEiiB0bAg=
|
||||
go.opentelemetry.io/otel/log v0.18.0/go.mod h1:KEV1kad0NofR3ycsiDH4Yjcoj0+8206I6Ox2QYFSNgI=
|
||||
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
|
||||
go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo=
|
||||
go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts=
|
||||
go.opentelemetry.io/otel/sdk/log v0.18.0 h1:n8OyZr7t7otkeTnPTbDNom6rW16TBYGtvyy2Gk6buQw=
|
||||
go.opentelemetry.io/otel/sdk/log v0.18.0/go.mod h1:C0+wxkTwKpOCZLrlJ3pewPiiQwpzycPI/u6W0Z9fuYk=
|
||||
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0 h1:l3mYuPsuBx6UKE47BVcPrZoZ0q/KER57vbj2qkgDLXA=
|
||||
go.opentelemetry.io/otel/sdk/log/logtest v0.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc=
|
||||
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
|
||||
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
|
||||
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
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=
|
||||
@@ -333,8 +347,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
||||
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
@@ -368,28 +382,28 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.197.0 h1:x6CwqQLsFiA5JKAiGyGBjc2bNtHtLddhJCE2IKuhhcQ=
|
||||
google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/api v0.214.0 h1:h2Gkq07OYi6kusGOaT/9rnNljuXmqPnaig7WGPmKbwA=
|
||||
google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU=
|
||||
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
|
||||
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
|
||||
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a h1:UIpYSuWdWHSzjwcAFRLjKcPXFZVVLXGEM23W+NWqipw=
|
||||
google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a/go.mod h1:9i1T9n4ZinTUZGgzENMi8MDDgbGC5mqTS75JAv6xN3A=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -399,8 +413,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
||||
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
||||
6.4.0
|
||||
7.3.2
|
||||
# Keep this pinned version in parity with cel-go
|
||||
@@ -1 +1,2 @@
|
||||
bazel-*
|
||||
MODULE.bazel.lock
|
||||
Vendored
-1
@@ -16,7 +16,6 @@ go_library(
|
||||
importpath = "cel.dev/expr",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//proto/cel/expr:google_rpc_status_go_proto",
|
||||
"@org_golang_google_protobuf//reflect/protoreflect",
|
||||
"@org_golang_google_protobuf//runtime/protoimpl",
|
||||
"@org_golang_google_protobuf//types/known/anypb",
|
||||
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
module(
|
||||
name = "cel-spec",
|
||||
)
|
||||
|
||||
bazel_dep(
|
||||
name = "bazel_skylib",
|
||||
version = "1.7.1",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "gazelle",
|
||||
version = "0.39.1",
|
||||
repo_name = "bazel_gazelle",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "protobuf",
|
||||
version = "27.1",
|
||||
repo_name = "com_google_protobuf",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "rules_cc",
|
||||
version = "0.0.17",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "rules_go",
|
||||
version = "0.53.0",
|
||||
repo_name = "io_bazel_rules_go",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "rules_java",
|
||||
version = "7.6.5",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "rules_proto",
|
||||
version = "7.0.2",
|
||||
)
|
||||
bazel_dep(
|
||||
name = "rules_python",
|
||||
version = "0.35.0",
|
||||
)
|
||||
|
||||
### PYTHON ###
|
||||
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
|
||||
python.toolchain(
|
||||
ignore_root_user_error = True,
|
||||
python_version = "3.11",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")
|
||||
go_sdk.download(version = "1.23.0")
|
||||
|
||||
go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
|
||||
go_deps.from_file(go_mod = "//:go.mod")
|
||||
use_repo(
|
||||
go_deps,
|
||||
"org_golang_google_protobuf",
|
||||
)
|
||||
Vendored
+10
-4
@@ -33,8 +33,7 @@ The required components of a system that supports CEL are:
|
||||
|
||||
* The textual representation of an expression as written by a developer. It is
|
||||
of similar syntax to expressions in C/C++/Java/JavaScript
|
||||
* A binary representation of an expression. It is an abstract syntax tree
|
||||
(AST).
|
||||
* A representation of the program's abstract syntax tree (AST).
|
||||
* A compiler library that converts the textual representation to the binary
|
||||
representation. This can be done ahead of time (in the control plane) or
|
||||
just before evaluation (in the data plane).
|
||||
@@ -43,6 +42,15 @@ The required components of a system that supports CEL are:
|
||||
* An evaluator library that takes the binary format in the context and
|
||||
produces a result, usually a Boolean.
|
||||
|
||||
For use cases which require persistence or cross-process communcation, it is
|
||||
highly recommended to serialize the type-checked expression as a protocol
|
||||
buffer. The CEL team will maintains canonical protocol buffers for ASTs and
|
||||
will keep these versions identical and wire-compatible in perpetuity:
|
||||
|
||||
* [CEL canonical](https://github.com/google/cel-spec/tree/master/proto/cel/expr)
|
||||
* [CEL v1alpha1](https://github.com/googleapis/googleapis/tree/master/google/api/expr/v1alpha1)
|
||||
|
||||
|
||||
Example of boolean conditions and object construction:
|
||||
|
||||
``` c
|
||||
@@ -61,5 +69,3 @@ For more detail, see:
|
||||
* [Language Definition](doc/langdef.md)
|
||||
|
||||
Released under the [Apache License](LICENSE).
|
||||
|
||||
Disclaimer: This is not an official Google product.
|
||||
Vendored
+10
-10
@@ -27,13 +27,13 @@ http_archive(
|
||||
],
|
||||
)
|
||||
|
||||
# googleapis as of 05/26/2023
|
||||
# googleapis as of 09/16/2024
|
||||
http_archive(
|
||||
name = "com_google_googleapis",
|
||||
strip_prefix = "googleapis-07c27163ac591955d736f3057b1619ece66f5b99",
|
||||
sha256 = "bd8e735d881fb829751ecb1a77038dda4a8d274c45490cb9fcf004583ee10571",
|
||||
strip_prefix = "googleapis-4082d5e51e8481f6ccc384cacd896f4e78f19dee",
|
||||
sha256 = "57319889d47578b3c89bf1b3f34888d796a8913d63b32d750a4cd12ed303c4e8",
|
||||
urls = [
|
||||
"https://github.com/googleapis/googleapis/archive/07c27163ac591955d736f3057b1619ece66f5b99.tar.gz",
|
||||
"https://github.com/googleapis/googleapis/archive/4082d5e51e8481f6ccc384cacd896f4e78f19dee.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -95,22 +95,22 @@ switched_rules_by_language(
|
||||
# Do *not* call *_dependencies(), etc, yet. See comment at the end.
|
||||
|
||||
# Generated Google APIs protos for Golang
|
||||
# Generated Google APIs protos for Golang 05/25/2023
|
||||
# Generated Google APIs protos for Golang 08/26/2024
|
||||
go_repository(
|
||||
name = "org_golang_google_genproto_googleapis_api",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "google.golang.org/genproto/googleapis/api",
|
||||
sum = "h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ=",
|
||||
version = "v0.0.0-20230525234035-dd9d682886f9",
|
||||
sum = "h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=",
|
||||
version = "v0.0.0-20240826202546-f6391c0de4c7",
|
||||
)
|
||||
|
||||
# Generated Google APIs protos for Golang 05/25/2023
|
||||
# Generated Google APIs protos for Golang 08/26/2024
|
||||
go_repository(
|
||||
name = "org_golang_google_genproto_googleapis_rpc",
|
||||
build_file_proto_mode = "disable_global",
|
||||
importpath = "google.golang.org/genproto/googleapis/rpc",
|
||||
sum = "h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=",
|
||||
version = "v0.0.0-20230525234030-28d5490b6b19",
|
||||
sum = "h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=",
|
||||
version = "v0.0.0-20240826202546-f6391c0de4c7",
|
||||
)
|
||||
|
||||
# gRPC deps
|
||||
|
||||
Whitespace-only changes.
+274
-475
File diff suppressed because it is too large.
Load diff
Vendored
+3
-3
@@ -1,8 +1,8 @@
|
||||
steps:
|
||||
- name: 'gcr.io/cloud-builders/bazel:6.4.0'
|
||||
- name: 'gcr.io/cloud-builders/bazel:7.3.2'
|
||||
entrypoint: bazel
|
||||
args: ['test', '--test_output=errors', '...']
|
||||
id: bazel-test
|
||||
args: ['build', '...']
|
||||
id: bazel-build
|
||||
waitFor: ['-']
|
||||
timeout: 15m
|
||||
options:
|
||||
|
||||
+168
-190
@@ -1,17 +1,18 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.5
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v5.27.1
|
||||
// source: cel/expr/eval.proto
|
||||
|
||||
package expr
|
||||
|
||||
import (
|
||||
status "google.golang.org/genproto/googleapis/rpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,21 +23,18 @@ const (
|
||||
)
|
||||
|
||||
type EvalState struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Values []*ExprValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||
Results []*EvalState_Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*ExprValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||
Results []*EvalState_Result `protobuf:"bytes,3,rep,name=results,proto3" json:"results,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EvalState) Reset() {
|
||||
*x = EvalState{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EvalState) String() string {
|
||||
@@ -47,7 +45,7 @@ func (*EvalState) ProtoMessage() {}
|
||||
|
||||
func (x *EvalState) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -77,25 +75,22 @@ func (x *EvalState) GetResults() []*EvalState_Result {
|
||||
}
|
||||
|
||||
type ExprValue struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Types that are assignable to Kind:
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Kind:
|
||||
//
|
||||
// *ExprValue_Value
|
||||
// *ExprValue_Error
|
||||
// *ExprValue_Unknown
|
||||
Kind isExprValue_Kind `protobuf_oneof:"kind"`
|
||||
Kind isExprValue_Kind `protobuf_oneof:"kind"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ExprValue) Reset() {
|
||||
*x = ExprValue{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ExprValue) String() string {
|
||||
@@ -106,7 +101,7 @@ func (*ExprValue) ProtoMessage() {}
|
||||
|
||||
func (x *ExprValue) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -121,30 +116,36 @@ func (*ExprValue) Descriptor() ([]byte, []int) {
|
||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (m *ExprValue) GetKind() isExprValue_Kind {
|
||||
if m != nil {
|
||||
return m.Kind
|
||||
func (x *ExprValue) GetKind() isExprValue_Kind {
|
||||
if x != nil {
|
||||
return x.Kind
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExprValue) GetValue() *Value {
|
||||
if x, ok := x.GetKind().(*ExprValue_Value); ok {
|
||||
return x.Value
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*ExprValue_Value); ok {
|
||||
return x.Value
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExprValue) GetError() *ErrorSet {
|
||||
if x, ok := x.GetKind().(*ExprValue_Error); ok {
|
||||
return x.Error
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*ExprValue_Error); ok {
|
||||
return x.Error
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ExprValue) GetUnknown() *UnknownSet {
|
||||
if x, ok := x.GetKind().(*ExprValue_Unknown); ok {
|
||||
return x.Unknown
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*ExprValue_Unknown); ok {
|
||||
return x.Unknown
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -172,20 +173,17 @@ func (*ExprValue_Error) isExprValue_Kind() {}
|
||||
func (*ExprValue_Unknown) isExprValue_Kind() {}
|
||||
|
||||
type ErrorSet struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Errors []*Status `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Errors []*status.Status `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ErrorSet) Reset() {
|
||||
*x = ErrorSet{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ErrorSet) String() string {
|
||||
@@ -196,7 +194,7 @@ func (*ErrorSet) ProtoMessage() {}
|
||||
|
||||
func (x *ErrorSet) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -211,28 +209,85 @@ func (*ErrorSet) Descriptor() ([]byte, []int) {
|
||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ErrorSet) GetErrors() []*status.Status {
|
||||
func (x *ErrorSet) GetErrors() []*Status {
|
||||
if x != nil {
|
||||
return x.Errors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UnknownSet struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
type Status struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
|
||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
||||
Details []*anypb.Any `protobuf:"bytes,3,rep,name=details,proto3" json:"details,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
Exprs []int64 `protobuf:"varint,1,rep,packed,name=exprs,proto3" json:"exprs,omitempty"`
|
||||
func (x *Status) Reset() {
|
||||
*x = Status{}
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Status) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Status) ProtoMessage() {}
|
||||
|
||||
func (x *Status) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Status.ProtoReflect.Descriptor instead.
|
||||
func (*Status) Descriptor() ([]byte, []int) {
|
||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Status) GetCode() int32 {
|
||||
if x != nil {
|
||||
return x.Code
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Status) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Status) GetDetails() []*anypb.Any {
|
||||
if x != nil {
|
||||
return x.Details
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UnknownSet struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Exprs []int64 `protobuf:"varint,1,rep,packed,name=exprs,proto3" json:"exprs,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UnknownSet) Reset() {
|
||||
*x = UnknownSet{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UnknownSet) String() string {
|
||||
@@ -242,8 +297,8 @@ func (x *UnknownSet) String() string {
|
||||
func (*UnknownSet) ProtoMessage() {}
|
||||
|
||||
func (x *UnknownSet) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -255,7 +310,7 @@ func (x *UnknownSet) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use UnknownSet.ProtoReflect.Descriptor instead.
|
||||
func (*UnknownSet) Descriptor() ([]byte, []int) {
|
||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{3}
|
||||
return file_cel_expr_eval_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *UnknownSet) GetExprs() []int64 {
|
||||
@@ -266,21 +321,18 @@ func (x *UnknownSet) GetExprs() []int64 {
|
||||
}
|
||||
|
||||
type EvalState_Result struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Expr int64 `protobuf:"varint,1,opt,name=expr,proto3" json:"expr,omitempty"`
|
||||
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Expr int64 `protobuf:"varint,1,opt,name=expr,proto3" json:"expr,omitempty"`
|
||||
Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EvalState_Result) Reset() {
|
||||
*x = EvalState_Result{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EvalState_Result) String() string {
|
||||
@@ -290,8 +342,8 @@ func (x *EvalState_Result) String() string {
|
||||
func (*EvalState_Result) ProtoMessage() {}
|
||||
|
||||
func (x *EvalState_Result) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
mi := &file_cel_expr_eval_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -322,78 +374,67 @@ func (x *EvalState_Result) GetValue() int64 {
|
||||
|
||||
var File_cel_expr_eval_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_cel_expr_eval_proto_rawDesc = []byte{
|
||||
0x0a, 0x13, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x65, 0x76, 0x61, 0x6c, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x1a,
|
||||
0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x72, 0x70,
|
||||
0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa2,
|
||||
0x01, 0x0a, 0x09, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2b, 0x0a, 0x06,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63,
|
||||
0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x73,
|
||||
0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x65, 0x6c,
|
||||
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x76, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e,
|
||||
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a,
|
||||
0x32, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x78, 0x70,
|
||||
0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x65, 0x78, 0x70, 0x72, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x09, 0x45, 0x78, 0x70, 0x72, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
|
||||
0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x65, 0x6c, 0x2e,
|
||||
0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52,
|
||||
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x30, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77,
|
||||
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78,
|
||||
0x70, 0x72, 0x2e, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52,
|
||||
0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64,
|
||||
0x22, 0x36, 0x0a, 0x08, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x12, 0x2a, 0x0a, 0x06,
|
||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x22, 0x0a, 0x0a, 0x55, 0x6e, 0x6b, 0x6e,
|
||||
0x6f, 0x77, 0x6e, 0x53, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x18,
|
||||
0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x05, 0x65, 0x78, 0x70, 0x72, 0x73, 0x42, 0x2c, 0x0a, 0x0c,
|
||||
0x64, 0x65, 0x76, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x09, 0x45, 0x76,
|
||||
0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64,
|
||||
0x65, 0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
const file_cel_expr_eval_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x13cel/expr/eval.proto\x12\bcel.expr\x1a\x19google/protobuf/any.proto\x1a\x14cel/expr/value.proto\"\xa2\x01\n" +
|
||||
"\tEvalState\x12+\n" +
|
||||
"\x06values\x18\x01 \x03(\v2\x13.cel.expr.ExprValueR\x06values\x124\n" +
|
||||
"\aresults\x18\x03 \x03(\v2\x1a.cel.expr.EvalState.ResultR\aresults\x1a2\n" +
|
||||
"\x06Result\x12\x12\n" +
|
||||
"\x04expr\x18\x01 \x01(\x03R\x04expr\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\x03R\x05value\"\x9a\x01\n" +
|
||||
"\tExprValue\x12'\n" +
|
||||
"\x05value\x18\x01 \x01(\v2\x0f.cel.expr.ValueH\x00R\x05value\x12*\n" +
|
||||
"\x05error\x18\x02 \x01(\v2\x12.cel.expr.ErrorSetH\x00R\x05error\x120\n" +
|
||||
"\aunknown\x18\x03 \x01(\v2\x14.cel.expr.UnknownSetH\x00R\aunknownB\x06\n" +
|
||||
"\x04kind\"4\n" +
|
||||
"\bErrorSet\x12(\n" +
|
||||
"\x06errors\x18\x01 \x03(\v2\x10.cel.expr.StatusR\x06errors\"f\n" +
|
||||
"\x06Status\x12\x12\n" +
|
||||
"\x04code\x18\x01 \x01(\x05R\x04code\x12\x18\n" +
|
||||
"\amessage\x18\x02 \x01(\tR\amessage\x12.\n" +
|
||||
"\adetails\x18\x03 \x03(\v2\x14.google.protobuf.AnyR\adetails\"\"\n" +
|
||||
"\n" +
|
||||
"UnknownSet\x12\x14\n" +
|
||||
"\x05exprs\x18\x01 \x03(\x03R\x05exprsB,\n" +
|
||||
"\fdev.cel.exprB\tEvalProtoP\x01Z\fcel.dev/expr\xf8\x01\x01b\x06proto3"
|
||||
|
||||
var (
|
||||
file_cel_expr_eval_proto_rawDescOnce sync.Once
|
||||
file_cel_expr_eval_proto_rawDescData = file_cel_expr_eval_proto_rawDesc
|
||||
file_cel_expr_eval_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_cel_expr_eval_proto_rawDescGZIP() []byte {
|
||||
file_cel_expr_eval_proto_rawDescOnce.Do(func() {
|
||||
file_cel_expr_eval_proto_rawDescData = protoimpl.X.CompressGZIP(file_cel_expr_eval_proto_rawDescData)
|
||||
file_cel_expr_eval_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_cel_expr_eval_proto_rawDesc), len(file_cel_expr_eval_proto_rawDesc)))
|
||||
})
|
||||
return file_cel_expr_eval_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_cel_expr_eval_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_cel_expr_eval_proto_goTypes = []interface{}{
|
||||
var file_cel_expr_eval_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_cel_expr_eval_proto_goTypes = []any{
|
||||
(*EvalState)(nil), // 0: cel.expr.EvalState
|
||||
(*ExprValue)(nil), // 1: cel.expr.ExprValue
|
||||
(*ErrorSet)(nil), // 2: cel.expr.ErrorSet
|
||||
(*UnknownSet)(nil), // 3: cel.expr.UnknownSet
|
||||
(*EvalState_Result)(nil), // 4: cel.expr.EvalState.Result
|
||||
(*Value)(nil), // 5: cel.expr.Value
|
||||
(*status.Status)(nil), // 6: google.rpc.Status
|
||||
(*Status)(nil), // 3: cel.expr.Status
|
||||
(*UnknownSet)(nil), // 4: cel.expr.UnknownSet
|
||||
(*EvalState_Result)(nil), // 5: cel.expr.EvalState.Result
|
||||
(*Value)(nil), // 6: cel.expr.Value
|
||||
(*anypb.Any)(nil), // 7: google.protobuf.Any
|
||||
}
|
||||
var file_cel_expr_eval_proto_depIdxs = []int32{
|
||||
1, // 0: cel.expr.EvalState.values:type_name -> cel.expr.ExprValue
|
||||
4, // 1: cel.expr.EvalState.results:type_name -> cel.expr.EvalState.Result
|
||||
5, // 2: cel.expr.ExprValue.value:type_name -> cel.expr.Value
|
||||
5, // 1: cel.expr.EvalState.results:type_name -> cel.expr.EvalState.Result
|
||||
6, // 2: cel.expr.ExprValue.value:type_name -> cel.expr.Value
|
||||
2, // 3: cel.expr.ExprValue.error:type_name -> cel.expr.ErrorSet
|
||||
3, // 4: cel.expr.ExprValue.unknown:type_name -> cel.expr.UnknownSet
|
||||
6, // 5: cel.expr.ErrorSet.errors:type_name -> google.rpc.Status
|
||||
6, // [6:6] is the sub-list for method output_type
|
||||
6, // [6:6] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
4, // 4: cel.expr.ExprValue.unknown:type_name -> cel.expr.UnknownSet
|
||||
3, // 5: cel.expr.ErrorSet.errors:type_name -> cel.expr.Status
|
||||
7, // 6: cel.expr.Status.details:type_name -> google.protobuf.Any
|
||||
7, // [7:7] is the sub-list for method output_type
|
||||
7, // [7:7] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_cel_expr_eval_proto_init() }
|
||||
@@ -402,69 +443,7 @@ func file_cel_expr_eval_proto_init() {
|
||||
return
|
||||
}
|
||||
file_cel_expr_value_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_cel_expr_eval_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*EvalState); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_eval_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ExprValue); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_eval_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ErrorSet); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_eval_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*UnknownSet); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_eval_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*EvalState_Result); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_cel_expr_eval_proto_msgTypes[1].OneofWrappers = []interface{}{
|
||||
file_cel_expr_eval_proto_msgTypes[1].OneofWrappers = []any{
|
||||
(*ExprValue_Value)(nil),
|
||||
(*ExprValue_Error)(nil),
|
||||
(*ExprValue_Unknown)(nil),
|
||||
@@ -473,9 +452,9 @@ func file_cel_expr_eval_proto_init() {
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_cel_expr_eval_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_cel_expr_eval_proto_rawDesc), len(file_cel_expr_eval_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 5,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
@@ -484,7 +463,6 @@ func file_cel_expr_eval_proto_init() {
|
||||
MessageInfos: file_cel_expr_eval_proto_msgTypes,
|
||||
}.Build()
|
||||
File_cel_expr_eval_proto = out.File
|
||||
file_cel_expr_eval_proto_rawDesc = nil
|
||||
file_cel_expr_eval_proto_goTypes = nil
|
||||
file_cel_expr_eval_proto_depIdxs = nil
|
||||
}
|
||||
+36
-77
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.5
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v5.27.1
|
||||
// source: cel/expr/explain.proto
|
||||
|
||||
package expr
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -20,23 +21,20 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Deprecated: Do not use.
|
||||
// Deprecated: Marked as deprecated in cel/expr/explain.proto.
|
||||
type Explain struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||
ExprSteps []*Explain_ExprStep `protobuf:"bytes,2,rep,name=expr_steps,json=exprSteps,proto3" json:"expr_steps,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||
ExprSteps []*Explain_ExprStep `protobuf:"bytes,2,rep,name=expr_steps,json=exprSteps,proto3" json:"expr_steps,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Explain) Reset() {
|
||||
*x = Explain{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_explain_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_explain_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Explain) String() string {
|
||||
@@ -47,7 +45,7 @@ func (*Explain) ProtoMessage() {}
|
||||
|
||||
func (x *Explain) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_explain_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -77,21 +75,18 @@ func (x *Explain) GetExprSteps() []*Explain_ExprStep {
|
||||
}
|
||||
|
||||
type Explain_ExprStep struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
ValueIndex int32 `protobuf:"varint,2,opt,name=value_index,json=valueIndex,proto3" json:"value_index,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
ValueIndex int32 `protobuf:"varint,2,opt,name=value_index,json=valueIndex,proto3" json:"value_index,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Explain_ExprStep) Reset() {
|
||||
*x = Explain_ExprStep{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_explain_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_explain_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Explain_ExprStep) String() string {
|
||||
@@ -102,7 +97,7 @@ func (*Explain_ExprStep) ProtoMessage() {}
|
||||
|
||||
func (x *Explain_ExprStep) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_explain_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -133,42 +128,33 @@ func (x *Explain_ExprStep) GetValueIndex() int32 {
|
||||
|
||||
var File_cel_expr_explain_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_cel_expr_explain_proto_rawDesc = []byte{
|
||||
0x0a, 0x16, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x6c, 0x61,
|
||||
0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78,
|
||||
0x70, 0x72, 0x1a, 0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x07, 0x45, 0x78, 0x70,
|
||||
0x6c, 0x61, 0x69, 0x6e, 0x12, 0x27, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x39, 0x0a,
|
||||
0x0a, 0x65, 0x78, 0x70, 0x72, 0x5f, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x78, 0x70,
|
||||
0x6c, 0x61, 0x69, 0x6e, 0x2e, 0x45, 0x78, 0x70, 0x72, 0x53, 0x74, 0x65, 0x70, 0x52, 0x09, 0x65,
|
||||
0x78, 0x70, 0x72, 0x53, 0x74, 0x65, 0x70, 0x73, 0x1a, 0x3b, 0x0a, 0x08, 0x45, 0x78, 0x70, 0x72,
|
||||
0x53, 0x74, 0x65, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x02, 0x69, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x69, 0x6e,
|
||||
0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x49, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x02, 0x18, 0x01, 0x42, 0x2f, 0x0a, 0x0c, 0x64, 0x65, 0x76,
|
||||
0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0c, 0x45, 0x78, 0x70, 0x6c, 0x61,
|
||||
0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64,
|
||||
0x65, 0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
}
|
||||
const file_cel_expr_explain_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x16cel/expr/explain.proto\x12\bcel.expr\x1a\x14cel/expr/value.proto\"\xae\x01\n" +
|
||||
"\aExplain\x12'\n" +
|
||||
"\x06values\x18\x01 \x03(\v2\x0f.cel.expr.ValueR\x06values\x129\n" +
|
||||
"\n" +
|
||||
"expr_steps\x18\x02 \x03(\v2\x1a.cel.expr.Explain.ExprStepR\texprSteps\x1a;\n" +
|
||||
"\bExprStep\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\x03R\x02id\x12\x1f\n" +
|
||||
"\vvalue_index\x18\x02 \x01(\x05R\n" +
|
||||
"valueIndex:\x02\x18\x01B/\n" +
|
||||
"\fdev.cel.exprB\fExplainProtoP\x01Z\fcel.dev/expr\xf8\x01\x01b\x06proto3"
|
||||
|
||||
var (
|
||||
file_cel_expr_explain_proto_rawDescOnce sync.Once
|
||||
file_cel_expr_explain_proto_rawDescData = file_cel_expr_explain_proto_rawDesc
|
||||
file_cel_expr_explain_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_cel_expr_explain_proto_rawDescGZIP() []byte {
|
||||
file_cel_expr_explain_proto_rawDescOnce.Do(func() {
|
||||
file_cel_expr_explain_proto_rawDescData = protoimpl.X.CompressGZIP(file_cel_expr_explain_proto_rawDescData)
|
||||
file_cel_expr_explain_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_cel_expr_explain_proto_rawDesc), len(file_cel_expr_explain_proto_rawDesc)))
|
||||
})
|
||||
return file_cel_expr_explain_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_cel_expr_explain_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_cel_expr_explain_proto_goTypes = []interface{}{
|
||||
var file_cel_expr_explain_proto_goTypes = []any{
|
||||
(*Explain)(nil), // 0: cel.expr.Explain
|
||||
(*Explain_ExprStep)(nil), // 1: cel.expr.Explain.ExprStep
|
||||
(*Value)(nil), // 2: cel.expr.Value
|
||||
@@ -189,37 +175,11 @@ func file_cel_expr_explain_proto_init() {
|
||||
return
|
||||
}
|
||||
file_cel_expr_value_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_cel_expr_explain_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Explain); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_explain_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Explain_ExprStep); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_cel_expr_explain_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_cel_expr_explain_proto_rawDesc), len(file_cel_expr_explain_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
@@ -230,7 +190,6 @@ func file_cel_expr_explain_proto_init() {
|
||||
MessageInfos: file_cel_expr_explain_proto_msgTypes,
|
||||
}.Build()
|
||||
File_cel_expr_explain_proto = out.File
|
||||
file_cel_expr_explain_proto_rawDesc = nil
|
||||
file_cel_expr_explain_proto_goTypes = nil
|
||||
file_cel_expr_explain_proto_depIdxs = nil
|
||||
}
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
#!/bin/sh
|
||||
bazel build //proto/test/...
|
||||
files=($(bazel aquery 'kind(proto, //proto/...)' | grep Outputs | grep "[.]pb[.]go" | sed 's/Outputs: \[//' | sed 's/\]//' | tr "," "\n"))
|
||||
bazel build //proto/cel/expr/conformance/...
|
||||
files=($(bazel aquery 'kind(proto, //proto/cel/expr/conformance/...)' | grep Outputs | grep "[.]pb[.]go" | sed 's/Outputs: \[//' | sed 's/\]//' | tr "," "\n"))
|
||||
for src in ${files[@]};
|
||||
do
|
||||
dst=$(echo $src | sed 's/\(.*\%\/github.com\/google\/cel-spec\/\(.*\)\)/\2/')
|
||||
dst=$(echo $src | sed 's/\(.*\/cel.dev\/expr\/\(.*\)\)/\2/')
|
||||
echo "copying $dst"
|
||||
$(cp $src $dst)
|
||||
done
|
||||
+320
-559
File diff suppressed because it is too large.
Load diff
+135
-213
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.5
|
||||
// protoc-gen-go v1.36.10
|
||||
// protoc v5.27.1
|
||||
// source: cel/expr/value.proto
|
||||
|
||||
package expr
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,11 +24,8 @@ const (
|
||||
)
|
||||
|
||||
type Value struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// Types that are assignable to Kind:
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Kind:
|
||||
//
|
||||
// *Value_NullValue
|
||||
// *Value_BoolValue
|
||||
@@ -41,16 +39,16 @@ type Value struct {
|
||||
// *Value_MapValue
|
||||
// *Value_ListValue
|
||||
// *Value_TypeValue
|
||||
Kind isValue_Kind `protobuf_oneof:"kind"`
|
||||
Kind isValue_Kind `protobuf_oneof:"kind"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Value) Reset() {
|
||||
*x = Value{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_value_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Value) String() string {
|
||||
@@ -61,7 +59,7 @@ func (*Value) ProtoMessage() {}
|
||||
|
||||
func (x *Value) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -76,93 +74,117 @@ func (*Value) Descriptor() ([]byte, []int) {
|
||||
return file_cel_expr_value_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (m *Value) GetKind() isValue_Kind {
|
||||
if m != nil {
|
||||
return m.Kind
|
||||
func (x *Value) GetKind() isValue_Kind {
|
||||
if x != nil {
|
||||
return x.Kind
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Value) GetNullValue() structpb.NullValue {
|
||||
if x, ok := x.GetKind().(*Value_NullValue); ok {
|
||||
return x.NullValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_NullValue); ok {
|
||||
return x.NullValue
|
||||
}
|
||||
}
|
||||
return structpb.NullValue(0)
|
||||
}
|
||||
|
||||
func (x *Value) GetBoolValue() bool {
|
||||
if x, ok := x.GetKind().(*Value_BoolValue); ok {
|
||||
return x.BoolValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_BoolValue); ok {
|
||||
return x.BoolValue
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Value) GetInt64Value() int64 {
|
||||
if x, ok := x.GetKind().(*Value_Int64Value); ok {
|
||||
return x.Int64Value
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_Int64Value); ok {
|
||||
return x.Int64Value
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Value) GetUint64Value() uint64 {
|
||||
if x, ok := x.GetKind().(*Value_Uint64Value); ok {
|
||||
return x.Uint64Value
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_Uint64Value); ok {
|
||||
return x.Uint64Value
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Value) GetDoubleValue() float64 {
|
||||
if x, ok := x.GetKind().(*Value_DoubleValue); ok {
|
||||
return x.DoubleValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_DoubleValue); ok {
|
||||
return x.DoubleValue
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Value) GetStringValue() string {
|
||||
if x, ok := x.GetKind().(*Value_StringValue); ok {
|
||||
return x.StringValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_StringValue); ok {
|
||||
return x.StringValue
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Value) GetBytesValue() []byte {
|
||||
if x, ok := x.GetKind().(*Value_BytesValue); ok {
|
||||
return x.BytesValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_BytesValue); ok {
|
||||
return x.BytesValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Value) GetEnumValue() *EnumValue {
|
||||
if x, ok := x.GetKind().(*Value_EnumValue); ok {
|
||||
return x.EnumValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_EnumValue); ok {
|
||||
return x.EnumValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Value) GetObjectValue() *anypb.Any {
|
||||
if x, ok := x.GetKind().(*Value_ObjectValue); ok {
|
||||
return x.ObjectValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_ObjectValue); ok {
|
||||
return x.ObjectValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Value) GetMapValue() *MapValue {
|
||||
if x, ok := x.GetKind().(*Value_MapValue); ok {
|
||||
return x.MapValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_MapValue); ok {
|
||||
return x.MapValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Value) GetListValue() *ListValue {
|
||||
if x, ok := x.GetKind().(*Value_ListValue); ok {
|
||||
return x.ListValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_ListValue); ok {
|
||||
return x.ListValue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Value) GetTypeValue() string {
|
||||
if x, ok := x.GetKind().(*Value_TypeValue); ok {
|
||||
return x.TypeValue
|
||||
if x != nil {
|
||||
if x, ok := x.Kind.(*Value_TypeValue); ok {
|
||||
return x.TypeValue
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -244,21 +266,18 @@ func (*Value_ListValue) isValue_Kind() {}
|
||||
func (*Value_TypeValue) isValue_Kind() {}
|
||||
|
||||
type EnumValue struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Value int32 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EnumValue) Reset() {
|
||||
*x = EnumValue{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_value_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EnumValue) String() string {
|
||||
@@ -269,7 +288,7 @@ func (*EnumValue) ProtoMessage() {}
|
||||
|
||||
func (x *EnumValue) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -299,20 +318,17 @@ func (x *EnumValue) GetValue() int32 {
|
||||
}
|
||||
|
||||
type ListValue struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*Value `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListValue) Reset() {
|
||||
*x = ListValue{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_value_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListValue) String() string {
|
||||
@@ -323,7 +339,7 @@ func (*ListValue) ProtoMessage() {}
|
||||
|
||||
func (x *ListValue) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -346,20 +362,17 @@ func (x *ListValue) GetValues() []*Value {
|
||||
}
|
||||
|
||||
type MapValue struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Entries []*MapValue_Entry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Entries []*MapValue_Entry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *MapValue) Reset() {
|
||||
*x = MapValue{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_value_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *MapValue) String() string {
|
||||
@@ -370,7 +383,7 @@ func (*MapValue) ProtoMessage() {}
|
||||
|
||||
func (x *MapValue) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -393,21 +406,18 @@ func (x *MapValue) GetEntries() []*MapValue_Entry {
|
||||
}
|
||||
|
||||
type MapValue_Entry struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Key *Value `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key *Value `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Value *Value `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *MapValue_Entry) Reset() {
|
||||
*x = MapValue_Entry{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
mi := &file_cel_expr_value_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *MapValue_Entry) String() string {
|
||||
@@ -418,7 +428,7 @@ func (*MapValue_Entry) ProtoMessage() {}
|
||||
|
||||
func (x *MapValue_Entry) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_cel_expr_value_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
@@ -449,83 +459,58 @@ func (x *MapValue_Entry) GetValue() *Value {
|
||||
|
||||
var File_cel_expr_value_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_cel_expr_value_proto_rawDesc = []byte{
|
||||
0x0a, 0x14, 0x63, 0x65, 0x6c, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72,
|
||||
0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72,
|
||||
0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9d, 0x04, 0x0a, 0x05, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x6e, 0x75, 0x6c, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4e, 0x75, 0x6c, 0x6c, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6e, 0x75, 0x6c, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x0b, 0x75, 0x69,
|
||||
0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x64, 0x6f, 0x75,
|
||||
0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x48,
|
||||
0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x23,
|
||||
0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65,
|
||||
0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x65, 0x6c,
|
||||
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48,
|
||||
0x00, 0x52, 0x09, 0x65, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x39, 0x0a, 0x0c,
|
||||
0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00, 0x52, 0x0b, 0x6f, 0x62, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x76,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x65, 0x6c,
|
||||
0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00,
|
||||
0x52, 0x08, 0x6d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x6c, 0x69,
|
||||
0x73, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
|
||||
0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x09, 0x6c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x12, 0x1f, 0x0a, 0x0a, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0f,
|
||||
0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x74, 0x79, 0x70, 0x65, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x42, 0x06, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x35, 0x0a, 0x09, 0x45, 0x6e, 0x75,
|
||||
0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x22, 0x34, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x27, 0x0a,
|
||||
0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
|
||||
0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x91, 0x01, 0x0a, 0x08, 0x4d, 0x61, 0x70, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e,
|
||||
0x4d, 0x61, 0x70, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07,
|
||||
0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x1a, 0x51, 0x0a, 0x05, 0x45, 0x6e, 0x74, 0x72, 0x79,
|
||||
0x12, 0x21, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
|
||||
0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2d, 0x0a, 0x0c, 0x64, 0x65,
|
||||
0x76, 0x2e, 0x63, 0x65, 0x6c, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x42, 0x0a, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x0c, 0x63, 0x65, 0x6c, 0x2e, 0x64, 0x65,
|
||||
0x76, 0x2f, 0x65, 0x78, 0x70, 0x72, 0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
const file_cel_expr_value_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x14cel/expr/value.proto\x12\bcel.expr\x1a\x19google/protobuf/any.proto\x1a\x1cgoogle/protobuf/struct.proto\"\x9d\x04\n" +
|
||||
"\x05Value\x12;\n" +
|
||||
"\n" +
|
||||
"null_value\x18\x01 \x01(\x0e2\x1a.google.protobuf.NullValueH\x00R\tnullValue\x12\x1f\n" +
|
||||
"\n" +
|
||||
"bool_value\x18\x02 \x01(\bH\x00R\tboolValue\x12!\n" +
|
||||
"\vint64_value\x18\x03 \x01(\x03H\x00R\n" +
|
||||
"int64Value\x12#\n" +
|
||||
"\fuint64_value\x18\x04 \x01(\x04H\x00R\vuint64Value\x12#\n" +
|
||||
"\fdouble_value\x18\x05 \x01(\x01H\x00R\vdoubleValue\x12#\n" +
|
||||
"\fstring_value\x18\x06 \x01(\tH\x00R\vstringValue\x12!\n" +
|
||||
"\vbytes_value\x18\a \x01(\fH\x00R\n" +
|
||||
"bytesValue\x124\n" +
|
||||
"\n" +
|
||||
"enum_value\x18\t \x01(\v2\x13.cel.expr.EnumValueH\x00R\tenumValue\x129\n" +
|
||||
"\fobject_value\x18\n" +
|
||||
" \x01(\v2\x14.google.protobuf.AnyH\x00R\vobjectValue\x121\n" +
|
||||
"\tmap_value\x18\v \x01(\v2\x12.cel.expr.MapValueH\x00R\bmapValue\x124\n" +
|
||||
"\n" +
|
||||
"list_value\x18\f \x01(\v2\x13.cel.expr.ListValueH\x00R\tlistValue\x12\x1f\n" +
|
||||
"\n" +
|
||||
"type_value\x18\x0f \x01(\tH\x00R\ttypeValueB\x06\n" +
|
||||
"\x04kind\"5\n" +
|
||||
"\tEnumValue\x12\x12\n" +
|
||||
"\x04type\x18\x01 \x01(\tR\x04type\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\x05R\x05value\"4\n" +
|
||||
"\tListValue\x12'\n" +
|
||||
"\x06values\x18\x01 \x03(\v2\x0f.cel.expr.ValueR\x06values\"\x91\x01\n" +
|
||||
"\bMapValue\x122\n" +
|
||||
"\aentries\x18\x01 \x03(\v2\x18.cel.expr.MapValue.EntryR\aentries\x1aQ\n" +
|
||||
"\x05Entry\x12!\n" +
|
||||
"\x03key\x18\x01 \x01(\v2\x0f.cel.expr.ValueR\x03key\x12%\n" +
|
||||
"\x05value\x18\x02 \x01(\v2\x0f.cel.expr.ValueR\x05valueB-\n" +
|
||||
"\fdev.cel.exprB\n" +
|
||||
"ValueProtoP\x01Z\fcel.dev/expr\xf8\x01\x01b\x06proto3"
|
||||
|
||||
var (
|
||||
file_cel_expr_value_proto_rawDescOnce sync.Once
|
||||
file_cel_expr_value_proto_rawDescData = file_cel_expr_value_proto_rawDesc
|
||||
file_cel_expr_value_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_cel_expr_value_proto_rawDescGZIP() []byte {
|
||||
file_cel_expr_value_proto_rawDescOnce.Do(func() {
|
||||
file_cel_expr_value_proto_rawDescData = protoimpl.X.CompressGZIP(file_cel_expr_value_proto_rawDescData)
|
||||
file_cel_expr_value_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_cel_expr_value_proto_rawDesc), len(file_cel_expr_value_proto_rawDesc)))
|
||||
})
|
||||
return file_cel_expr_value_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_cel_expr_value_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_cel_expr_value_proto_goTypes = []interface{}{
|
||||
var file_cel_expr_value_proto_goTypes = []any{
|
||||
(*Value)(nil), // 0: cel.expr.Value
|
||||
(*EnumValue)(nil), // 1: cel.expr.EnumValue
|
||||
(*ListValue)(nil), // 2: cel.expr.ListValue
|
||||
@@ -556,69 +541,7 @@ func file_cel_expr_value_proto_init() {
|
||||
if File_cel_expr_value_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_cel_expr_value_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Value); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_value_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*EnumValue); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_value_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ListValue); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_value_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*MapValue); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_cel_expr_value_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*MapValue_Entry); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
file_cel_expr_value_proto_msgTypes[0].OneofWrappers = []interface{}{
|
||||
file_cel_expr_value_proto_msgTypes[0].OneofWrappers = []any{
|
||||
(*Value_NullValue)(nil),
|
||||
(*Value_BoolValue)(nil),
|
||||
(*Value_Int64Value)(nil),
|
||||
@@ -636,7 +559,7 @@ func file_cel_expr_value_proto_init() {
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_cel_expr_value_proto_rawDesc,
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_cel_expr_value_proto_rawDesc), len(file_cel_expr_value_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
@@ -647,7 +570,6 @@ func file_cel_expr_value_proto_init() {
|
||||
MessageInfos: file_cel_expr_value_proto_msgTypes,
|
||||
}.Build()
|
||||
File_cel_expr_value_proto = out.File
|
||||
file_cel_expr_value_proto_rawDesc = nil
|
||||
file_cel_expr_value_proto_goTypes = nil
|
||||
file_cel_expr_value_proto_depIdxs = nil
|
||||
}
|
||||
+107
@@ -1,5 +1,112 @@
|
||||
# Changelog
|
||||
|
||||
## [0.13.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.1...auth/v0.13.0) (2024-12-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** Add logging support ([#11079](https://github.com/googleapis/google-cloud-go/issues/11079)) ([c80e31d](https://github.com/googleapis/google-cloud-go/commit/c80e31df5ecb33a810be3dfb9d9e27ac531aa91d))
|
||||
* **auth:** Pass logger from auth layer to metadata package ([#11288](https://github.com/googleapis/google-cloud-go/issues/11288)) ([b552efd](https://github.com/googleapis/google-cloud-go/commit/b552efd6ab34e5dfded18438e0fbfd925805614f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Check compute cred type before non-default flag for DP ([#11255](https://github.com/googleapis/google-cloud-go/issues/11255)) ([4347ca1](https://github.com/googleapis/google-cloud-go/commit/4347ca141892be8ae813399b4b437662a103bc90))
|
||||
|
||||
## [0.12.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.12.0...auth/v0.12.1) (2024-12-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Correct typo in link ([#11160](https://github.com/googleapis/google-cloud-go/issues/11160)) ([af6fb46](https://github.com/googleapis/google-cloud-go/commit/af6fb46d7cd694ddbe8c9d63bc4cdcd62b9fb2c1))
|
||||
|
||||
## [0.12.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.11.0...auth/v0.12.0) (2024-12-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** Add support for providing custom certificate URL ([#11006](https://github.com/googleapis/google-cloud-go/issues/11006)) ([ebf3657](https://github.com/googleapis/google-cloud-go/commit/ebf36579724afb375d3974cf1da38f703e3b7dbc)), refs [#11005](https://github.com/googleapis/google-cloud-go/issues/11005)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Ensure endpoints are present in Validator ([#11209](https://github.com/googleapis/google-cloud-go/issues/11209)) ([106cd53](https://github.com/googleapis/google-cloud-go/commit/106cd53309facaef1b8ea78376179f523f6912b9)), refs [#11006](https://github.com/googleapis/google-cloud-go/issues/11006) [#11190](https://github.com/googleapis/google-cloud-go/issues/11190) [#11189](https://github.com/googleapis/google-cloud-go/issues/11189) [#11188](https://github.com/googleapis/google-cloud-go/issues/11188)
|
||||
|
||||
## [0.11.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.2...auth/v0.11.0) (2024-11-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** Add universe domain support to mTLS ([#11159](https://github.com/googleapis/google-cloud-go/issues/11159)) ([117748b](https://github.com/googleapis/google-cloud-go/commit/117748ba1cfd4ae62a6a4feb7e30951cb2bc9344))
|
||||
|
||||
## [0.10.2](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.1...auth/v0.10.2) (2024-11-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Restore use of grpc.Dial ([#11118](https://github.com/googleapis/google-cloud-go/issues/11118)) ([2456b94](https://github.com/googleapis/google-cloud-go/commit/2456b943b7b8aaabd4d8bfb7572c0f477ae0db45)), refs [#7556](https://github.com/googleapis/google-cloud-go/issues/7556)
|
||||
|
||||
## [0.10.1](https://github.com/googleapis/google-cloud-go/compare/auth/v0.10.0...auth/v0.10.1) (2024-11-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Restore Application Default Credentials support to idtoken ([#11083](https://github.com/googleapis/google-cloud-go/issues/11083)) ([8771f2e](https://github.com/googleapis/google-cloud-go/commit/8771f2ea9807ab822083808e0678392edff3b4f2))
|
||||
* **auth:** Skip impersonate universe domain check if empty ([#11086](https://github.com/googleapis/google-cloud-go/issues/11086)) ([87159c1](https://github.com/googleapis/google-cloud-go/commit/87159c1059d4a18d1367ce62746a838a94964ab6))
|
||||
|
||||
## [0.10.0](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.9...auth/v0.10.0) (2024-10-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **auth:** Add universe domain support to credentials/impersonate ([#10953](https://github.com/googleapis/google-cloud-go/issues/10953)) ([e06cb64](https://github.com/googleapis/google-cloud-go/commit/e06cb6499f7eda3aef08ab18ff197016f667684b))
|
||||
|
||||
## [0.9.9](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.8...auth/v0.9.9) (2024-10-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Fallback cert lookups for missing files ([#11013](https://github.com/googleapis/google-cloud-go/issues/11013)) ([bd76695](https://github.com/googleapis/google-cloud-go/commit/bd766957ec238b7c40ddbabb369e612dc9b07313)), refs [#10844](https://github.com/googleapis/google-cloud-go/issues/10844)
|
||||
* **auth:** Replace MDS endpoint universe_domain with universe-domain ([#11000](https://github.com/googleapis/google-cloud-go/issues/11000)) ([6a1586f](https://github.com/googleapis/google-cloud-go/commit/6a1586f2ce9974684affaea84e7b629313b4d114))
|
||||
|
||||
## [0.9.8](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.7...auth/v0.9.8) (2024-10-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Restore OpenTelemetry handling in transports ([#10968](https://github.com/googleapis/google-cloud-go/issues/10968)) ([08c6d04](https://github.com/googleapis/google-cloud-go/commit/08c6d04901c1a20e219b2d86df41dbaa6d7d7b55)), refs [#10962](https://github.com/googleapis/google-cloud-go/issues/10962)
|
||||
* **auth:** Try talk to plaintext S2A if credentials can not be found for mTLS-S2A ([#10941](https://github.com/googleapis/google-cloud-go/issues/10941)) ([0f0bf2d](https://github.com/googleapis/google-cloud-go/commit/0f0bf2d18c97dd8b65bcf0099f0802b5631c6287))
|
||||
|
||||
## [0.9.7](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.6...auth/v0.9.7) (2024-10-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Restore support for non-default service accounts for DirectPath ([#10937](https://github.com/googleapis/google-cloud-go/issues/10937)) ([a38650e](https://github.com/googleapis/google-cloud-go/commit/a38650edbf420223077498cafa537aec74b37aad)), refs [#10907](https://github.com/googleapis/google-cloud-go/issues/10907)
|
||||
|
||||
## [0.9.6](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.5...auth/v0.9.6) (2024-09-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Make aws credentials provider retrieve fresh credentials ([#10920](https://github.com/googleapis/google-cloud-go/issues/10920)) ([250fbf8](https://github.com/googleapis/google-cloud-go/commit/250fbf87d858d865e399a241b7e537c4ff0c3dd8))
|
||||
|
||||
## [0.9.5](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.4...auth/v0.9.5) (2024-09-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Restore support for GOOGLE_CLOUD_UNIVERSE_DOMAIN env ([#10915](https://github.com/googleapis/google-cloud-go/issues/10915)) ([94caaaa](https://github.com/googleapis/google-cloud-go/commit/94caaaa061362d0e00ef6214afcc8a0a3e7ebfb2))
|
||||
* **auth:** Skip directpath credentials overwrite when it's not on GCE ([#10833](https://github.com/googleapis/google-cloud-go/issues/10833)) ([7e5e8d1](https://github.com/googleapis/google-cloud-go/commit/7e5e8d10b761b0a6e43e19a028528db361bc07b1))
|
||||
* **auth:** Use new context for non-blocking token refresh ([#10919](https://github.com/googleapis/google-cloud-go/issues/10919)) ([cf7102d](https://github.com/googleapis/google-cloud-go/commit/cf7102d33a21be1e5a9d47a49456b3a57c43b350))
|
||||
|
||||
## [0.9.4](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.3...auth/v0.9.4) (2024-09-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth:** Enable self-signed JWT for non-GDU universe domain ([#10831](https://github.com/googleapis/google-cloud-go/issues/10831)) ([f9869f7](https://github.com/googleapis/google-cloud-go/commit/f9869f7903cfd34d1b97c25d0dc5669d2c5138e6))
|
||||
|
||||
## [0.9.3](https://github.com/googleapis/google-cloud-go/compare/auth/v0.9.2...auth/v0.9.3) (2024-09-03)
|
||||
|
||||
|
||||
|
||||
+39
-3
@@ -1,4 +1,40 @@
|
||||
# auth
|
||||
# Google Auth Library for Go
|
||||
|
||||
This module is currently EXPERIMENTAL and under active development. It is not
|
||||
yet intended to be used.
|
||||
[](https://pkg.go.dev/cloud.google.com/go/auth)
|
||||
|
||||
## Install
|
||||
|
||||
``` bash
|
||||
go get cloud.google.com/go/auth@latest
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The most common way this library is used is transitively, by default, from any
|
||||
of our Go client libraries.
|
||||
|
||||
### Notable use-cases
|
||||
|
||||
- To create a credential directly please see examples in the
|
||||
[credentials](https://pkg.go.dev/cloud.google.com/go/auth/credentials)
|
||||
package.
|
||||
- To create a authenticated HTTP client please see examples in the
|
||||
[httptransport](https://pkg.go.dev/cloud.google.com/go/auth/httptransport)
|
||||
package.
|
||||
- To create a authenticated gRPC connection please see examples in the
|
||||
[grpctransport](https://pkg.go.dev/cloud.google.com/go/auth/grpctransport)
|
||||
package.
|
||||
- To create an ID token please see examples in the
|
||||
[idtoken](https://pkg.go.dev/cloud.google.com/go/auth/credentials/idtoken)
|
||||
package.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome. Please, see the
|
||||
[CONTRIBUTING](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md)
|
||||
document for details.
|
||||
|
||||
Please note that this project is released with a Contributor Code of Conduct.
|
||||
By participating in this project you agree to abide by its terms.
|
||||
See [Contributor Code of Conduct](https://github.com/GoogleCloudPlatform/google-cloud-go/blob/main/CONTRIBUTING.md#contributor-code-of-conduct)
|
||||
for more information.
|
||||
+22
-16
@@ -24,6 +24,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/jwt"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -227,9 +229,7 @@ type CredentialsOptions struct {
|
||||
UniverseDomainProvider CredentialsPropertyProvider
|
||||
}
|
||||
|
||||
// NewCredentials returns new [Credentials] from the provided options. Most users
|
||||
// will want to build this object a function from the
|
||||
// [cloud.google.com/go/auth/credentials] package.
|
||||
// NewCredentials returns new [Credentials] from the provided options.
|
||||
func NewCredentials(opts *CredentialsOptions) *Credentials {
|
||||
creds := &Credentials{
|
||||
TokenProvider: opts.TokenProvider,
|
||||
@@ -242,8 +242,8 @@ func NewCredentials(opts *CredentialsOptions) *Credentials {
|
||||
return creds
|
||||
}
|
||||
|
||||
// CachedTokenProviderOptions provided options for configuring a
|
||||
// CachedTokenProvider.
|
||||
// CachedTokenProviderOptions provides options for configuring a cached
|
||||
// [TokenProvider].
|
||||
type CachedTokenProviderOptions struct {
|
||||
// DisableAutoRefresh makes the TokenProvider always return the same token,
|
||||
// even if it is expired. The default is false. Optional.
|
||||
@@ -253,7 +253,7 @@ type CachedTokenProviderOptions struct {
|
||||
// seconds. Optional.
|
||||
ExpireEarly time.Duration
|
||||
// DisableAsyncRefresh configures a synchronous workflow that refreshes
|
||||
// stale tokens while blocking. The default is false. Optional.
|
||||
// tokens in a blocking manner. The default is false. Optional.
|
||||
DisableAsyncRefresh bool
|
||||
}
|
||||
|
||||
@@ -280,12 +280,7 @@ func (ctpo *CachedTokenProviderOptions) blockingRefresh() bool {
|
||||
|
||||
// NewCachedTokenProvider wraps a [TokenProvider] to cache the tokens returned
|
||||
// by the underlying provider. By default it will refresh tokens asynchronously
|
||||
// (non-blocking mode) within a window that starts 3 minutes and 45 seconds
|
||||
// before they expire. The asynchronous (non-blocking) refresh can be changed to
|
||||
// a synchronous (blocking) refresh using the
|
||||
// CachedTokenProviderOptions.DisableAsyncRefresh option. The time-before-expiry
|
||||
// duration can be configured using the CachedTokenProviderOptions.ExpireEarly
|
||||
// option.
|
||||
// a few minutes before they expire.
|
||||
func NewCachedTokenProvider(tp TokenProvider, opts *CachedTokenProviderOptions) TokenProvider {
|
||||
if ctp, ok := tp.(*cachedTokenProvider); ok {
|
||||
return ctp
|
||||
@@ -328,7 +323,9 @@ func (c *cachedTokenProvider) tokenNonBlocking(ctx context.Context) (*Token, err
|
||||
defer c.mu.Unlock()
|
||||
return c.cachedToken, nil
|
||||
case stale:
|
||||
c.tokenAsync(ctx)
|
||||
// Call tokenAsync with a new Context because the user-provided context
|
||||
// may have a short timeout incompatible with async token refresh.
|
||||
c.tokenAsync(context.Background())
|
||||
// Return the stale token immediately to not block customer requests to Cloud services.
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
@@ -343,13 +340,14 @@ func (c *cachedTokenProvider) tokenState() tokenState {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
t := c.cachedToken
|
||||
now := timeNow()
|
||||
if t == nil || t.Value == "" {
|
||||
return invalid
|
||||
} else if t.Expiry.IsZero() {
|
||||
return fresh
|
||||
} else if timeNow().After(t.Expiry.Round(0)) {
|
||||
} else if now.After(t.Expiry.Round(0)) {
|
||||
return invalid
|
||||
} else if timeNow().After(t.Expiry.Round(0).Add(-c.expireEarly)) {
|
||||
} else if now.After(t.Expiry.Round(0).Add(-c.expireEarly)) {
|
||||
return stale
|
||||
}
|
||||
return fresh
|
||||
@@ -494,6 +492,11 @@ type Options2LO struct {
|
||||
// UseIDToken requests that the token returned be an ID token if one is
|
||||
// returned from the server. Optional.
|
||||
UseIDToken bool
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (o *Options2LO) client() *http.Client {
|
||||
@@ -524,12 +527,13 @@ func New2LOTokenProvider(opts *Options2LO) (TokenProvider, error) {
|
||||
if err := opts.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tokenProvider2LO{opts: opts, Client: opts.client()}, nil
|
||||
return tokenProvider2LO{opts: opts, Client: opts.client(), logger: internallog.New(opts.Logger)}, nil
|
||||
}
|
||||
|
||||
type tokenProvider2LO struct {
|
||||
opts *Options2LO
|
||||
Client *http.Client
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (tp tokenProvider2LO) Token(ctx context.Context) (*Token, error) {
|
||||
@@ -564,10 +568,12 @@ func (tp tokenProvider2LO) Token(ctx context.Context) (*Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
tp.logger.DebugContext(ctx, "2LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
||||
resp, body, err := internal.DoRequest(tp.Client, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("auth: cannot fetch token: %w", err)
|
||||
}
|
||||
tp.logger.DebugContext(ctx, "2LO token response", "response", internallog.HTTPResponse(resp, body))
|
||||
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
||||
return nil, &Error{
|
||||
Response: resp,
|
||||
|
||||
+8
-4
@@ -37,8 +37,11 @@ var (
|
||||
|
||||
// computeTokenProvider creates a [cloud.google.com/go/auth.TokenProvider] that
|
||||
// uses the metadata service to retrieve tokens.
|
||||
func computeTokenProvider(opts *DetectOptions) auth.TokenProvider {
|
||||
return auth.NewCachedTokenProvider(computeProvider{scopes: opts.Scopes}, &auth.CachedTokenProviderOptions{
|
||||
func computeTokenProvider(opts *DetectOptions, client *metadata.Client) auth.TokenProvider {
|
||||
return auth.NewCachedTokenProvider(&computeProvider{
|
||||
scopes: opts.Scopes,
|
||||
client: client,
|
||||
}, &auth.CachedTokenProviderOptions{
|
||||
ExpireEarly: opts.EarlyTokenRefresh,
|
||||
DisableAsyncRefresh: opts.DisableAsyncRefresh,
|
||||
})
|
||||
@@ -47,6 +50,7 @@ func computeTokenProvider(opts *DetectOptions) auth.TokenProvider {
|
||||
// computeProvider fetches tokens from the google cloud metadata service.
|
||||
type computeProvider struct {
|
||||
scopes []string
|
||||
client *metadata.Client
|
||||
}
|
||||
|
||||
type metadataTokenResp struct {
|
||||
@@ -55,7 +59,7 @@ type metadataTokenResp struct {
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
|
||||
func (cs computeProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
func (cs *computeProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
tokenURI, err := url.Parse(computeTokenURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -65,7 +69,7 @@ func (cs computeProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
v.Set("scopes", strings.Join(cs.scopes, ","))
|
||||
tokenURI.RawQuery = v.Encode()
|
||||
}
|
||||
tokenJSON, err := metadata.GetWithContext(ctx, tokenURI.String())
|
||||
tokenJSON, err := cs.client.GetWithContext(ctx, tokenURI.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
||||
}
|
||||
|
||||
+20
-3
@@ -19,6 +19,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/credsfile"
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -96,12 +98,17 @@ func DetectDefault(opts *DetectOptions) (*auth.Credentials, error) {
|
||||
}
|
||||
|
||||
if OnGCE() {
|
||||
metadataClient := metadata.NewWithOptions(&metadata.Options{
|
||||
Logger: opts.logger(),
|
||||
})
|
||||
return auth.NewCredentials(&auth.CredentialsOptions{
|
||||
TokenProvider: computeTokenProvider(opts),
|
||||
TokenProvider: computeTokenProvider(opts, metadataClient),
|
||||
ProjectIDProvider: auth.CredentialsPropertyFunc(func(ctx context.Context) (string, error) {
|
||||
return metadata.ProjectIDWithContext(ctx)
|
||||
return metadataClient.ProjectIDWithContext(ctx)
|
||||
}),
|
||||
UniverseDomainProvider: &internal.ComputeUniverseDomainProvider{},
|
||||
UniverseDomainProvider: &internal.ComputeUniverseDomainProvider{
|
||||
MetadataClient: metadataClient,
|
||||
},
|
||||
}), nil
|
||||
}
|
||||
|
||||
@@ -158,6 +165,11 @@ type DetectOptions struct {
|
||||
// The default value is "googleapis.com". This option is ignored for
|
||||
// authentication flows that do not support universe domain. Optional.
|
||||
UniverseDomain string
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (o *DetectOptions) validate() error {
|
||||
@@ -193,6 +205,10 @@ func (o *DetectOptions) client() *http.Client {
|
||||
return internal.DefaultClient()
|
||||
}
|
||||
|
||||
func (o *DetectOptions) logger() *slog.Logger {
|
||||
return internallog.New(o.Logger)
|
||||
}
|
||||
|
||||
func readCredentialsFile(filename string, opts *DetectOptions) (*auth.Credentials, error) {
|
||||
b, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
@@ -253,6 +269,7 @@ func clientCredConfigFromJSON(b []byte, opts *DetectOptions) *auth.Options3LO {
|
||||
AuthURL: c.AuthURI,
|
||||
TokenURL: c.TokenURI,
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
||||
AuthHandlerOpts: handleOpts,
|
||||
// TODO(codyoss): refactor this out. We need to add in auto-detection
|
||||
|
||||
+12
@@ -124,8 +124,14 @@ func resolveUniverseDomain(optsUniverseDomain, fileUniverseDomain string) string
|
||||
}
|
||||
|
||||
func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||
ud := resolveUniverseDomain(opts.UniverseDomain, f.UniverseDomain)
|
||||
if opts.UseSelfSignedJWT {
|
||||
return configureSelfSignedJWT(f, opts)
|
||||
} else if ud != "" && ud != internalauth.DefaultUniverseDomain {
|
||||
// For non-GDU universe domains, token exchange is impossible and services
|
||||
// must support self-signed JWTs.
|
||||
opts.UseSelfSignedJWT = true
|
||||
return configureSelfSignedJWT(f, opts)
|
||||
}
|
||||
opts2LO := &auth.Options2LO{
|
||||
Email: f.ClientEmail,
|
||||
@@ -135,6 +141,7 @@ func handleServiceAccount(f *credsfile.ServiceAccountFile, opts *DetectOptions)
|
||||
TokenURL: f.TokenURL,
|
||||
Subject: opts.Subject,
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
}
|
||||
if opts2LO.TokenURL == "" {
|
||||
opts2LO.TokenURL = jwtTokenURL
|
||||
@@ -153,6 +160,7 @@ func handleUserCredential(f *credsfile.UserCredentialsFile, opts *DetectOptions)
|
||||
EarlyTokenExpiry: opts.EarlyTokenRefresh,
|
||||
RefreshToken: f.RefreshToken,
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
}
|
||||
return auth.New3LOTokenProvider(opts3LO)
|
||||
}
|
||||
@@ -171,6 +179,7 @@ func handleExternalAccount(f *credsfile.ExternalAccountFile, opts *DetectOptions
|
||||
Scopes: opts.scopes(),
|
||||
WorkforcePoolUserProject: f.WorkforcePoolUserProject,
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
IsDefaultClient: opts.Client == nil,
|
||||
}
|
||||
if f.ServiceAccountImpersonation != nil {
|
||||
@@ -189,6 +198,7 @@ func handleExternalAccountAuthorizedUser(f *credsfile.ExternalAccountAuthorizedU
|
||||
ClientSecret: f.ClientSecret,
|
||||
Scopes: opts.scopes(),
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
}
|
||||
return externalaccountuser.NewTokenProvider(externalOpts)
|
||||
}
|
||||
@@ -208,6 +218,7 @@ func handleImpersonatedServiceAccount(f *credsfile.ImpersonatedServiceAccountFil
|
||||
Tp: tp,
|
||||
Delegates: f.Delegates,
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -215,5 +226,6 @@ func handleGDCHServiceAccount(f *credsfile.GDCHServiceAccountFile, opts *DetectO
|
||||
return gdch.NewTokenProvider(f, &gdch.Options{
|
||||
STSAudience: opts.STSAudience,
|
||||
Client: opts.client(),
|
||||
Logger: opts.logger(),
|
||||
})
|
||||
}
|
||||
Generated
Vendored
+29
-20
@@ -23,6 +23,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -87,6 +89,7 @@ type awsSubjectProvider struct {
|
||||
reqOpts *RequestOptions
|
||||
|
||||
Client *http.Client
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (sp *awsSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
||||
@@ -94,32 +97,30 @@ func (sp *awsSubjectProvider) subjectToken(ctx context.Context) (string, error)
|
||||
if sp.RegionalCredVerificationURL == "" {
|
||||
sp.RegionalCredVerificationURL = defaultRegionalCredentialVerificationURL
|
||||
}
|
||||
if sp.requestSigner == nil {
|
||||
headers := make(map[string]string)
|
||||
if sp.shouldUseMetadataServer() {
|
||||
awsSessionToken, err := sp.getAWSSessionToken(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if awsSessionToken != "" {
|
||||
headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
|
||||
}
|
||||
}
|
||||
|
||||
awsSecurityCredentials, err := sp.getSecurityCredentials(ctx, headers)
|
||||
headers := make(map[string]string)
|
||||
if sp.shouldUseMetadataServer() {
|
||||
awsSessionToken, err := sp.getAWSSessionToken(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if sp.region, err = sp.getRegion(ctx, headers); err != nil {
|
||||
return "", err
|
||||
}
|
||||
sp.requestSigner = &awsRequestSigner{
|
||||
RegionName: sp.region,
|
||||
AwsSecurityCredentials: awsSecurityCredentials,
|
||||
|
||||
if awsSessionToken != "" {
|
||||
headers[awsIMDSv2SessionTokenHeader] = awsSessionToken
|
||||
}
|
||||
}
|
||||
|
||||
awsSecurityCredentials, err := sp.getSecurityCredentials(ctx, headers)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if sp.region, err = sp.getRegion(ctx, headers); err != nil {
|
||||
return "", err
|
||||
}
|
||||
sp.requestSigner = &awsRequestSigner{
|
||||
RegionName: sp.region,
|
||||
AwsSecurityCredentials: awsSecurityCredentials,
|
||||
}
|
||||
|
||||
// Generate the signed request to AWS STS GetCallerIdentity API.
|
||||
// Use the required regional endpoint. Otherwise, the request will fail.
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", strings.Replace(sp.RegionalCredVerificationURL, "{region}", sp.region, 1), nil)
|
||||
@@ -194,10 +195,12 @@ func (sp *awsSubjectProvider) getAWSSessionToken(ctx context.Context) (string, e
|
||||
}
|
||||
req.Header.Set(awsIMDSv2SessionTTLHeader, awsIMDSv2SessionTTL)
|
||||
|
||||
sp.logger.DebugContext(ctx, "aws session token request", "request", internallog.HTTPRequest(req, nil))
|
||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sp.logger.DebugContext(ctx, "aws session token response", "response", internallog.HTTPResponse(resp, body))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("credentials: unable to retrieve AWS session token: %s", body)
|
||||
}
|
||||
@@ -227,10 +230,12 @@ func (sp *awsSubjectProvider) getRegion(ctx context.Context, headers map[string]
|
||||
for name, value := range headers {
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
sp.logger.DebugContext(ctx, "aws region request", "request", internallog.HTTPRequest(req, nil))
|
||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sp.logger.DebugContext(ctx, "aws region response", "response", internallog.HTTPResponse(resp, body))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("credentials: unable to retrieve AWS region - %s", body)
|
||||
}
|
||||
@@ -285,10 +290,12 @@ func (sp *awsSubjectProvider) getMetadataSecurityCredentials(ctx context.Context
|
||||
for name, value := range headers {
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
sp.logger.DebugContext(ctx, "aws security credential request", "request", internallog.HTTPRequest(req, nil))
|
||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
sp.logger.DebugContext(ctx, "aws security credential response", "response", internallog.HTTPResponse(resp, body))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return result, fmt.Errorf("credentials: unable to retrieve AWS security credentials - %s", body)
|
||||
}
|
||||
@@ -310,10 +317,12 @@ func (sp *awsSubjectProvider) getMetadataRoleName(ctx context.Context, headers m
|
||||
req.Header.Add(name, value)
|
||||
}
|
||||
|
||||
sp.logger.DebugContext(ctx, "aws metadata role request", "request", internallog.HTTPRequest(req, nil))
|
||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sp.logger.DebugContext(ctx, "aws metadata role response", "response", internallog.HTTPResponse(resp, body))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("credentials: unable to retrieve AWS role name - %s", body)
|
||||
}
|
||||
|
||||
Generated
Vendored
+22
-1
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -28,6 +29,7 @@ import (
|
||||
"cloud.google.com/go/auth/credentials/internal/impersonate"
|
||||
"cloud.google.com/go/auth/credentials/internal/stsexchange"
|
||||
"cloud.google.com/go/auth/internal/credsfile"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -104,6 +106,11 @@ type Options struct {
|
||||
// This is important for X509 credentials which should create a new client if the default was used
|
||||
// but should respect a client explicitly passed in by the user.
|
||||
IsDefaultClient bool
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
// SubjectTokenProvider can be used to supply a subject token to exchange for a
|
||||
@@ -224,6 +231,7 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
||||
return nil, err
|
||||
}
|
||||
opts.resolveTokenURL()
|
||||
logger := internallog.New(opts.Logger)
|
||||
stp, err := newSubjectTokenProvider(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -238,6 +246,7 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
||||
client: client,
|
||||
opts: opts,
|
||||
stp: stp,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
if opts.ServiceAccountImpersonationURL == "" {
|
||||
@@ -254,6 +263,7 @@ func NewTokenProvider(opts *Options) (auth.TokenProvider, error) {
|
||||
Scopes: scopes,
|
||||
Tp: auth.NewCachedTokenProvider(tp, nil),
|
||||
TokenLifetimeSeconds: opts.ServiceAccountImpersonationLifetimeSeconds,
|
||||
Logger: logger,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -269,6 +279,7 @@ type subjectTokenProvider interface {
|
||||
// tokenProvider is the provider that handles external credentials. It is used to retrieve Tokens.
|
||||
type tokenProvider struct {
|
||||
client *http.Client
|
||||
logger *slog.Logger
|
||||
opts *Options
|
||||
stp subjectTokenProvider
|
||||
}
|
||||
@@ -310,6 +321,7 @@ func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
Authentication: clientAuth,
|
||||
Headers: header,
|
||||
ExtraOpts: options,
|
||||
Logger: tp.logger,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -330,12 +342,14 @@ func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
// newSubjectTokenProvider determines the type of credsfile.CredentialSource needed to create a
|
||||
// subjectTokenProvider
|
||||
func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
|
||||
logger := internallog.New(o.Logger)
|
||||
reqOpts := &RequestOptions{Audience: o.Audience, SubjectTokenType: o.SubjectTokenType}
|
||||
if o.AwsSecurityCredentialsProvider != nil {
|
||||
return &awsSubjectProvider{
|
||||
securityCredentialsProvider: o.AwsSecurityCredentialsProvider,
|
||||
TargetResource: o.Audience,
|
||||
reqOpts: reqOpts,
|
||||
logger: logger,
|
||||
}, nil
|
||||
} else if o.SubjectTokenProvider != nil {
|
||||
return &programmaticProvider{stp: o.SubjectTokenProvider, opts: reqOpts}, nil
|
||||
@@ -352,6 +366,7 @@ func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
|
||||
CredVerificationURL: o.CredentialSource.URL,
|
||||
TargetResource: o.Audience,
|
||||
Client: o.Client,
|
||||
logger: logger,
|
||||
}
|
||||
if o.CredentialSource.IMDSv2SessionTokenURL != "" {
|
||||
awsProvider.IMDSv2SessionTokenURL = o.CredentialSource.IMDSv2SessionTokenURL
|
||||
@@ -362,7 +377,13 @@ func newSubjectTokenProvider(o *Options) (subjectTokenProvider, error) {
|
||||
} else if o.CredentialSource.File != "" {
|
||||
return &fileSubjectProvider{File: o.CredentialSource.File, Format: o.CredentialSource.Format}, nil
|
||||
} else if o.CredentialSource.URL != "" {
|
||||
return &urlSubjectProvider{URL: o.CredentialSource.URL, Headers: o.CredentialSource.Headers, Format: o.CredentialSource.Format, Client: o.Client}, nil
|
||||
return &urlSubjectProvider{
|
||||
URL: o.CredentialSource.URL,
|
||||
Headers: o.CredentialSource.Headers,
|
||||
Format: o.CredentialSource.Format,
|
||||
Client: o.Client,
|
||||
Logger: logger,
|
||||
}, nil
|
||||
} else if o.CredentialSource.Executable != nil {
|
||||
ec := o.CredentialSource.Executable
|
||||
if ec.Command == "" {
|
||||
|
||||
Generated
Vendored
+5
@@ -19,10 +19,12 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/credsfile"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -38,6 +40,7 @@ type urlSubjectProvider struct {
|
||||
Headers map[string]string
|
||||
Format *credsfile.Format
|
||||
Client *http.Client
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (sp *urlSubjectProvider) subjectToken(ctx context.Context) (string, error) {
|
||||
@@ -49,10 +52,12 @@ func (sp *urlSubjectProvider) subjectToken(ctx context.Context) (string, error)
|
||||
for key, val := range sp.Headers {
|
||||
req.Header.Add(key, val)
|
||||
}
|
||||
sp.Logger.DebugContext(ctx, "url subject token request", "request", internallog.HTTPRequest(req, nil))
|
||||
resp, body, err := internal.DoRequest(sp.Client, req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("credentials: invalid response when retrieving subject token: %w", err)
|
||||
}
|
||||
sp.Logger.DebugContext(ctx, "url subject token response", "response", internallog.HTTPResponse(resp, body))
|
||||
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
||||
return "", fmt.Errorf("credentials: status code %d: %s", c, body)
|
||||
}
|
||||
|
||||
Generated
Vendored
+5
@@ -17,12 +17,14 @@ package externalaccountuser
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
"cloud.google.com/go/auth/credentials/internal/stsexchange"
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
// Options stores the configuration for fetching tokens with external authorized
|
||||
@@ -51,6 +53,8 @@ type Options struct {
|
||||
|
||||
// Client for token request.
|
||||
Client *http.Client
|
||||
// Logger for logging.
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (c *Options) validate() bool {
|
||||
@@ -90,6 +94,7 @@ func (tp *tokenProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
RefreshToken: opts.RefreshToken,
|
||||
Authentication: clientAuth,
|
||||
Headers: headers,
|
||||
Logger: internallog.New(tp.o.Logger),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+12
-5
@@ -16,12 +16,13 @@ package gdch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"crypto"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/credsfile"
|
||||
"cloud.google.com/go/auth/internal/jwt"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,6 +53,7 @@ var (
|
||||
type Options struct {
|
||||
STSAudience string
|
||||
Client *http.Client
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewTokenProvider returns a [cloud.google.com/go/auth.TokenProvider] from a
|
||||
@@ -62,7 +65,7 @@ func NewTokenProvider(f *credsfile.GDCHServiceAccountFile, o *Options) (auth.Tok
|
||||
if o.STSAudience == "" {
|
||||
return nil, errors.New("credentials: STSAudience must be set for the GDCH auth flows")
|
||||
}
|
||||
pk, err := internal.ParseKey([]byte(f.PrivateKey))
|
||||
signer, err := internal.ParseKey([]byte(f.PrivateKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -75,10 +78,11 @@ func NewTokenProvider(f *credsfile.GDCHServiceAccountFile, o *Options) (auth.Tok
|
||||
serviceIdentity: fmt.Sprintf("system:serviceaccount:%s:%s", f.Project, f.Name),
|
||||
tokenURL: f.TokenURL,
|
||||
aud: o.STSAudience,
|
||||
pk: pk,
|
||||
signer: signer,
|
||||
pkID: f.PrivateKeyID,
|
||||
certPool: certPool,
|
||||
client: o.Client,
|
||||
logger: internallog.New(o.Logger),
|
||||
}
|
||||
return tp, nil
|
||||
}
|
||||
@@ -97,11 +101,12 @@ type gdchProvider struct {
|
||||
serviceIdentity string
|
||||
tokenURL string
|
||||
aud string
|
||||
pk *rsa.PrivateKey
|
||||
signer crypto.Signer
|
||||
pkID string
|
||||
certPool *x509.CertPool
|
||||
|
||||
client *http.Client
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
@@ -120,7 +125,7 @@ func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
Type: jwt.HeaderType,
|
||||
KeyID: string(g.pkID),
|
||||
}
|
||||
payload, err := jwt.EncodeJWS(&h, &claims, g.pk)
|
||||
payload, err := jwt.EncodeJWS(&h, &claims, g.signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -136,10 +141,12 @@ func (g gdchProvider) Token(ctx context.Context) (*auth.Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
g.logger.DebugContext(ctx, "gdch token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
||||
resp, body, err := internal.DoRequest(g.client, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("credentials: cannot fetch token: %w", err)
|
||||
}
|
||||
g.logger.DebugContext(ctx, "gdch token response", "response", internallog.HTTPResponse(resp, body))
|
||||
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
|
||||
return nil, &auth.Error{
|
||||
Response: resp,
|
||||
|
||||
+10
@@ -20,11 +20,13 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -74,6 +76,11 @@ type Options struct {
|
||||
// Client configures the underlying client used to make network requests
|
||||
// when fetching tokens. Required.
|
||||
Client *http.Client
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (o *Options) validate() error {
|
||||
@@ -88,6 +95,7 @@ func (o *Options) validate() error {
|
||||
|
||||
// Token performs the exchange to get a temporary service account token to allow access to GCP.
|
||||
func (o *Options) Token(ctx context.Context) (*auth.Token, error) {
|
||||
logger := internallog.New(o.Logger)
|
||||
lifetime := defaultTokenLifetime
|
||||
if o.TokenLifetimeSeconds != 0 {
|
||||
lifetime = fmt.Sprintf("%ds", o.TokenLifetimeSeconds)
|
||||
@@ -109,10 +117,12 @@ func (o *Options) Token(ctx context.Context) (*auth.Token, error) {
|
||||
if err := setAuthHeader(ctx, o.Tp, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logger.DebugContext(ctx, "impersonated token request", "request", internallog.HTTPRequest(req, b))
|
||||
resp, body, err := internal.DoRequest(o.Client, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("credentials: unable to generate access token: %w", err)
|
||||
}
|
||||
logger.DebugContext(ctx, "impersonated token response", "response", internallog.HTTPResponse(resp, body))
|
||||
if c := resp.StatusCode; c < http.StatusOK || c >= http.StatusMultipleChoices {
|
||||
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
|
||||
}
|
||||
|
||||
+6
@@ -19,6 +19,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -26,6 +27,7 @@ import (
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,6 +42,7 @@ const (
|
||||
// Options stores the configuration for making an sts exchange request.
|
||||
type Options struct {
|
||||
Client *http.Client
|
||||
Logger *slog.Logger
|
||||
Endpoint string
|
||||
Request *TokenRequest
|
||||
Authentication ClientAuthentication
|
||||
@@ -80,6 +83,7 @@ func ExchangeToken(ctx context.Context, opts *Options) (*TokenResponse, error) {
|
||||
func doRequest(ctx context.Context, opts *Options, data url.Values) (*TokenResponse, error) {
|
||||
opts.Authentication.InjectAuthentication(data, opts.Headers)
|
||||
encodedData := data.Encode()
|
||||
logger := internallog.New(opts.Logger)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", opts.Endpoint, strings.NewReader(encodedData))
|
||||
if err != nil {
|
||||
@@ -93,10 +97,12 @@ func doRequest(ctx context.Context, opts *Options, data url.Values) (*TokenRespo
|
||||
}
|
||||
req.Header.Set("Content-Length", strconv.Itoa(len(encodedData)))
|
||||
|
||||
logger.DebugContext(ctx, "sts token request", "request", internallog.HTTPRequest(req, []byte(encodedData)))
|
||||
resp, body, err := internal.DoRequest(opts.Client, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("credentials: invalid response from Secure Token Server: %w", err)
|
||||
}
|
||||
logger.DebugContext(ctx, "sts token response", "response", internallog.HTTPResponse(resp, body))
|
||||
if c := resp.StatusCode; c < http.StatusOK || c > http.StatusMultipleChoices {
|
||||
return nil, fmt.Errorf("credentials: status code %d: %s", c, body)
|
||||
}
|
||||
|
||||
+14
-6
@@ -16,8 +16,10 @@ package credentials
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"crypto"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -35,7 +37,10 @@ var (
|
||||
// configureSelfSignedJWT uses the private key in the service account to create
|
||||
// a JWT without making a network call.
|
||||
func configureSelfSignedJWT(f *credsfile.ServiceAccountFile, opts *DetectOptions) (auth.TokenProvider, error) {
|
||||
pk, err := internal.ParseKey([]byte(f.PrivateKey))
|
||||
if len(opts.scopes()) == 0 && opts.Audience == "" {
|
||||
return nil, errors.New("credentials: both scopes and audience are empty")
|
||||
}
|
||||
signer, err := internal.ParseKey([]byte(f.PrivateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("credentials: could not parse key: %w", err)
|
||||
}
|
||||
@@ -43,8 +48,9 @@ func configureSelfSignedJWT(f *credsfile.ServiceAccountFile, opts *DetectOptions
|
||||
email: f.ClientEmail,
|
||||
audience: opts.Audience,
|
||||
scopes: opts.scopes(),
|
||||
pk: pk,
|
||||
signer: signer,
|
||||
pkID: f.PrivateKeyID,
|
||||
logger: opts.logger(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -52,8 +58,9 @@ type selfSignedTokenProvider struct {
|
||||
email string
|
||||
audience string
|
||||
scopes []string
|
||||
pk *rsa.PrivateKey
|
||||
signer crypto.Signer
|
||||
pkID string
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (tp *selfSignedTokenProvider) Token(context.Context) (*auth.Token, error) {
|
||||
@@ -73,9 +80,10 @@ func (tp *selfSignedTokenProvider) Token(context.Context) (*auth.Token, error) {
|
||||
Type: jwt.HeaderType,
|
||||
KeyID: string(tp.pkID),
|
||||
}
|
||||
msg, err := jwt.EncodeJWS(h, c, tp.pk)
|
||||
tok, err := jwt.EncodeJWS(h, c, tp.signer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("credentials: could not encode JWT: %w", err)
|
||||
}
|
||||
return &auth.Token{Value: msg, Type: internal.TokenTypeBearer, Expiry: exp}, nil
|
||||
tp.logger.Debug("created self-signed JWT", "token", tok)
|
||||
return &auth.Token{Value: tok, Type: internal.TokenTypeBearer, Expiry: exp}, nil
|
||||
}
|
||||
+6
-3
@@ -22,7 +22,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
"cloud.google.com/go/auth/internal/compute"
|
||||
"google.golang.org/grpc"
|
||||
grpcgoogle "google.golang.org/grpc/credentials/google"
|
||||
)
|
||||
@@ -55,7 +55,7 @@ func checkDirectPathEndPoint(endpoint string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, _ *Options) bool {
|
||||
func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, o *Options) bool {
|
||||
if tp == nil {
|
||||
return false
|
||||
}
|
||||
@@ -69,6 +69,9 @@ func isTokenProviderDirectPathCompatible(tp auth.TokenProvider, _ *Options) bool
|
||||
if tok.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||
return false
|
||||
}
|
||||
if o.InternalOptions != nil && o.InternalOptions.EnableNonDefaultSAForDirectPath {
|
||||
return true
|
||||
}
|
||||
if tok.MetadataString("auth.google.serviceAccount") != "default" {
|
||||
return false
|
||||
}
|
||||
@@ -91,7 +94,7 @@ func isDirectPathXdsUsed(o *Options) bool {
|
||||
// configuration allows the use of direct path. If it does not the provided
|
||||
// grpcOpts and endpoint are returned.
|
||||
func configureDirectPath(grpcOpts []grpc.DialOption, opts *Options, endpoint string, creds *auth.Credentials) ([]grpc.DialOption, string) {
|
||||
if isDirectPathEnabled(endpoint, opts) && metadata.OnGCE() && isTokenProviderDirectPathCompatible(creds, opts) {
|
||||
if isDirectPathEnabled(endpoint, opts) && compute.OnComputeEngine() && isTokenProviderDirectPathCompatible(creds, opts) {
|
||||
// Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
|
||||
grpcOpts = []grpc.DialOption{
|
||||
grpc.WithCredentialsBundle(grpcgoogle.NewDefaultCredentialsWithOptions(grpcgoogle.DefaultCredentialsOptions{PerRPCCreds: &grpcCredentialsProvider{creds: creds}}))}
|
||||
|
||||
+59
-12
@@ -21,16 +21,21 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
"cloud.google.com/go/auth/credentials"
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/transport"
|
||||
"go.opencensus.io/plugin/ocgrpc"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||
"google.golang.org/grpc"
|
||||
grpccreds "google.golang.org/grpc/credentials"
|
||||
grpcinsecure "google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/stats"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -48,6 +53,27 @@ var (
|
||||
timeoutDialerOption grpc.DialOption
|
||||
)
|
||||
|
||||
// otelStatsHandler is a singleton otelgrpc.clientHandler to be used across
|
||||
// all dial connections to avoid the memory leak documented in
|
||||
// https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4226
|
||||
//
|
||||
// TODO: When this module depends on a version of otelgrpc containing the fix,
|
||||
// replace this singleton with inline usage for simplicity.
|
||||
// The fix should be in https://github.com/open-telemetry/opentelemetry-go/pull/5797.
|
||||
var (
|
||||
initOtelStatsHandlerOnce sync.Once
|
||||
otelStatsHandler stats.Handler
|
||||
)
|
||||
|
||||
// otelGRPCStatsHandler returns singleton otelStatsHandler for reuse across all
|
||||
// dial connections.
|
||||
func otelGRPCStatsHandler() stats.Handler {
|
||||
initOtelStatsHandlerOnce.Do(func() {
|
||||
otelStatsHandler = otelgrpc.NewClientHandler()
|
||||
})
|
||||
return otelStatsHandler
|
||||
}
|
||||
|
||||
// ClientCertProvider is a function that returns a TLS client certificate to be
|
||||
// used when opening TLS connections. It follows the same semantics as
|
||||
// [crypto/tls.Config.GetClientCertificate].
|
||||
@@ -92,6 +118,11 @@ type Options struct {
|
||||
// APIKey specifies an API key to be used as the basis for authentication.
|
||||
// If set DetectOpts are ignored.
|
||||
APIKey string
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
|
||||
// InternalOptions are NOT meant to be set directly by consumers of this
|
||||
// package, they should only be set by generated client code.
|
||||
@@ -107,6 +138,10 @@ func (o *Options) client() *http.Client {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Options) logger() *slog.Logger {
|
||||
return internallog.New(o.Logger)
|
||||
}
|
||||
|
||||
func (o *Options) validate() error {
|
||||
if o == nil {
|
||||
return errors.New("grpctransport: opts required to be non-nil")
|
||||
@@ -148,6 +183,9 @@ func (o *Options) resolveDetectOptions() *credentials.DetectOptions {
|
||||
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
|
||||
do.TokenURL = credentials.GoogleMTLSTokenURL
|
||||
}
|
||||
if do.Logger == nil {
|
||||
do.Logger = o.logger()
|
||||
}
|
||||
return do
|
||||
}
|
||||
|
||||
@@ -216,6 +254,7 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
|
||||
ClientCertProvider: opts.ClientCertProvider,
|
||||
Client: opts.client(),
|
||||
UniverseDomain: opts.UniverseDomain,
|
||||
Logger: opts.logger(),
|
||||
}
|
||||
if io := opts.InternalOptions; io != nil {
|
||||
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate
|
||||
@@ -293,10 +332,10 @@ func dial(ctx context.Context, secure bool, opts *Options) (*grpc.ClientConn, er
|
||||
// Add tracing, but before the other options, so that clients can override the
|
||||
// gRPC stats handler.
|
||||
// This assumes that gRPC options are processed in order, left to right.
|
||||
grpcOpts = addOCStatsHandler(grpcOpts, opts)
|
||||
grpcOpts = addOpenTelemetryStatsHandler(grpcOpts, opts)
|
||||
grpcOpts = append(grpcOpts, opts.GRPCDialOpts...)
|
||||
|
||||
return grpc.NewClient(endpoint, grpcOpts...)
|
||||
return grpc.Dial(endpoint, grpcOpts...)
|
||||
}
|
||||
|
||||
// grpcKeyProvider satisfies https://pkg.go.dev/google.golang.org/grpc/credentials#PerRPCCredentials.
|
||||
@@ -330,15 +369,23 @@ type grpcCredentialsProvider struct {
|
||||
clientUniverseDomain string
|
||||
}
|
||||
|
||||
// getClientUniverseDomain returns the default service domain for a given Cloud universe.
|
||||
// The default value is "googleapis.com". This is the universe domain
|
||||
// configured for the client, which will be compared to the universe domain
|
||||
// that is separately configured for the credentials.
|
||||
// getClientUniverseDomain returns the default service domain for a given Cloud
|
||||
// universe, with the following precedence:
|
||||
//
|
||||
// 1. A non-empty option.WithUniverseDomain or similar client option.
|
||||
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
|
||||
// 3. The default value "googleapis.com".
|
||||
//
|
||||
// This is the universe domain configured for the client, which will be compared
|
||||
// to the universe domain that is separately configured for the credentials.
|
||||
func (c *grpcCredentialsProvider) getClientUniverseDomain() string {
|
||||
if c.clientUniverseDomain == "" {
|
||||
return internal.DefaultUniverseDomain
|
||||
if c.clientUniverseDomain != "" {
|
||||
return c.clientUniverseDomain
|
||||
}
|
||||
return c.clientUniverseDomain
|
||||
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
|
||||
return envUD
|
||||
}
|
||||
return internal.DefaultUniverseDomain
|
||||
}
|
||||
|
||||
func (c *grpcCredentialsProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||
@@ -383,9 +430,9 @@ func (c *grpcCredentialsProvider) RequireTransportSecurity() bool {
|
||||
return c.secure
|
||||
}
|
||||
|
||||
func addOCStatsHandler(dialOpts []grpc.DialOption, opts *Options) []grpc.DialOption {
|
||||
func addOpenTelemetryStatsHandler(dialOpts []grpc.DialOption, opts *Options) []grpc.DialOption {
|
||||
if opts.DisableTelemetry {
|
||||
return dialOpts
|
||||
}
|
||||
return append(dialOpts, grpc.WithStatsHandler(&ocgrpc.ClientHandler{}))
|
||||
return append(dialOpts, grpc.WithStatsHandler(otelGRPCStatsHandler()))
|
||||
}
|
||||
+23
-2
@@ -20,12 +20,14 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
detect "cloud.google.com/go/auth/credentials"
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/transport"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
// ClientCertProvider is a function that returns a TLS client certificate to be
|
||||
@@ -69,6 +71,11 @@ type Options struct {
|
||||
// configured for the client, which will be compared to the universe domain
|
||||
// that is separately configured for the credentials.
|
||||
UniverseDomain string
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
|
||||
// InternalOptions are NOT meant to be set directly by consumers of this
|
||||
// package, they should only be set by generated client code.
|
||||
@@ -101,6 +108,10 @@ func (o *Options) client() *http.Client {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Options) logger() *slog.Logger {
|
||||
return internallog.New(o.Logger)
|
||||
}
|
||||
|
||||
func (o *Options) resolveDetectOptions() *detect.DetectOptions {
|
||||
io := o.InternalOptions
|
||||
// soft-clone these so we are not updating a ref the user holds and may reuse
|
||||
@@ -125,6 +136,9 @@ func (o *Options) resolveDetectOptions() *detect.DetectOptions {
|
||||
do.Client = transport.DefaultHTTPClientWithTLS(tlsConfig)
|
||||
do.TokenURL = detect.GoogleMTLSTokenURL
|
||||
}
|
||||
if do.Logger == nil {
|
||||
do.Logger = o.logger()
|
||||
}
|
||||
return do
|
||||
}
|
||||
|
||||
@@ -147,14 +161,21 @@ type InternalOptions struct {
|
||||
// service.
|
||||
DefaultScopes []string
|
||||
// SkipValidation bypasses validation on Options. It should only be used
|
||||
// internally for clients that needs more control over their transport.
|
||||
// internally for clients that need more control over their transport.
|
||||
SkipValidation bool
|
||||
// SkipUniverseDomainValidation skips the verification that the universe
|
||||
// domain configured for the client matches the universe domain configured
|
||||
// for the credentials. It should only be used internally for clients that
|
||||
// need more control over their transport. The default is false.
|
||||
SkipUniverseDomainValidation bool
|
||||
}
|
||||
|
||||
// AddAuthorizationMiddleware adds a middleware to the provided client's
|
||||
// transport that sets the Authorization header with the value produced by the
|
||||
// provided [cloud.google.com/go/auth.Credentials]. An error is returned only
|
||||
// if client or creds is nil.
|
||||
//
|
||||
// This function does not support setting a universe domain value on the client.
|
||||
func AddAuthorizationMiddleware(client *http.Client, creds *auth.Credentials) error {
|
||||
if client == nil || creds == nil {
|
||||
return fmt.Errorf("httptransport: client and tp must not be nil")
|
||||
@@ -173,7 +194,6 @@ func AddAuthorizationMiddleware(client *http.Client, creds *auth.Credentials) er
|
||||
client.Transport = &authTransport{
|
||||
creds: creds,
|
||||
base: base,
|
||||
// TODO(quartzmo): Somehow set clientUniverseDomain from impersonate calls.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -191,6 +211,7 @@ func NewClient(opts *Options) (*http.Client, error) {
|
||||
ClientCertProvider: opts.ClientCertProvider,
|
||||
Client: opts.client(),
|
||||
UniverseDomain: opts.UniverseDomain,
|
||||
Logger: opts.logger(),
|
||||
}
|
||||
if io := opts.InternalOptions; io != nil {
|
||||
tOpts.DefaultEndpointTemplate = io.DefaultEndpointTemplate
|
||||
|
||||
-93
@@ -1,93 +0,0 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httptransport
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
"go.opencensus.io/trace/propagation"
|
||||
)
|
||||
|
||||
const (
|
||||
httpHeaderMaxSize = 200
|
||||
cloudTraceHeader = `X-Cloud-Trace-Context`
|
||||
)
|
||||
|
||||
// asserts the httpFormat fulfills this foreign interface
|
||||
var _ propagation.HTTPFormat = (*httpFormat)(nil)
|
||||
|
||||
// httpFormat implements propagation.httpFormat to propagate
|
||||
// traces in HTTP headers for Google Cloud Platform and Cloud Trace.
|
||||
type httpFormat struct{}
|
||||
|
||||
// SpanContextFromRequest extracts a Cloud Trace span context from incoming requests.
|
||||
func (f *httpFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
|
||||
h := req.Header.Get(cloudTraceHeader)
|
||||
// See https://cloud.google.com/trace/docs/faq for the header HTTPFormat.
|
||||
// Return if the header is empty or missing, or if the header is unreasonably
|
||||
// large, to avoid making unnecessary copies of a large string.
|
||||
if h == "" || len(h) > httpHeaderMaxSize {
|
||||
return trace.SpanContext{}, false
|
||||
}
|
||||
|
||||
// Parse the trace id field.
|
||||
slash := strings.Index(h, `/`)
|
||||
if slash == -1 {
|
||||
return trace.SpanContext{}, false
|
||||
}
|
||||
tid, h := h[:slash], h[slash+1:]
|
||||
|
||||
buf, err := hex.DecodeString(tid)
|
||||
if err != nil {
|
||||
return trace.SpanContext{}, false
|
||||
}
|
||||
copy(sc.TraceID[:], buf)
|
||||
|
||||
// Parse the span id field.
|
||||
spanstr := h
|
||||
semicolon := strings.Index(h, `;`)
|
||||
if semicolon != -1 {
|
||||
spanstr, h = h[:semicolon], h[semicolon+1:]
|
||||
}
|
||||
sid, err := strconv.ParseUint(spanstr, 10, 64)
|
||||
if err != nil {
|
||||
return trace.SpanContext{}, false
|
||||
}
|
||||
binary.BigEndian.PutUint64(sc.SpanID[:], sid)
|
||||
|
||||
// Parse the options field, options field is optional.
|
||||
if !strings.HasPrefix(h, "o=") {
|
||||
return sc, true
|
||||
}
|
||||
o, err := strconv.ParseUint(h[2:], 10, 32)
|
||||
if err != nil {
|
||||
return trace.SpanContext{}, false
|
||||
}
|
||||
sc.TraceOptions = trace.TraceOptions(o)
|
||||
return sc, true
|
||||
}
|
||||
|
||||
// SpanContextToRequest modifies the given request to include a Cloud Trace header.
|
||||
func (f *httpFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
|
||||
sid := binary.BigEndian.Uint64(sc.SpanID[:])
|
||||
header := fmt.Sprintf("%s/%d;o=%d", hex.EncodeToString(sc.TraceID[:]), sid, int64(sc.TraceOptions))
|
||||
req.Header.Set(cloudTraceHeader, header)
|
||||
}
|
||||
+33
-19
@@ -19,6 +19,7 @@ import (
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/auth"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"cloud.google.com/go/auth/internal/transport"
|
||||
"cloud.google.com/go/auth/internal/transport/cert"
|
||||
"go.opencensus.io/plugin/ochttp"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -41,7 +42,7 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
|
||||
headers: headers,
|
||||
}
|
||||
var trans http.RoundTripper = ht
|
||||
trans = addOCTransport(trans, opts)
|
||||
trans = addOpenTelemetryTransport(trans, opts)
|
||||
switch {
|
||||
case opts.DisableAuthentication:
|
||||
// Do nothing.
|
||||
@@ -81,11 +82,16 @@ func newTransport(base http.RoundTripper, opts *Options) (http.RoundTripper, err
|
||||
headers.Set(quotaProjectHeaderKey, qp)
|
||||
}
|
||||
}
|
||||
var skipUD bool
|
||||
if iOpts := opts.InternalOptions; iOpts != nil {
|
||||
skipUD = iOpts.SkipUniverseDomainValidation
|
||||
}
|
||||
creds.TokenProvider = auth.NewCachedTokenProvider(creds.TokenProvider, nil)
|
||||
trans = &authTransport{
|
||||
base: trans,
|
||||
creds: creds,
|
||||
clientUniverseDomain: opts.UniverseDomain,
|
||||
base: trans,
|
||||
creds: creds,
|
||||
clientUniverseDomain: opts.UniverseDomain,
|
||||
skipUniverseDomainValidation: skipUD,
|
||||
}
|
||||
}
|
||||
return trans, nil
|
||||
@@ -162,29 +168,37 @@ func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return rt.RoundTrip(&newReq)
|
||||
}
|
||||
|
||||
func addOCTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
|
||||
func addOpenTelemetryTransport(trans http.RoundTripper, opts *Options) http.RoundTripper {
|
||||
if opts.DisableTelemetry {
|
||||
return trans
|
||||
}
|
||||
return &ochttp.Transport{
|
||||
Base: trans,
|
||||
Propagation: &httpFormat{},
|
||||
}
|
||||
return otelhttp.NewTransport(trans)
|
||||
}
|
||||
|
||||
type authTransport struct {
|
||||
creds *auth.Credentials
|
||||
base http.RoundTripper
|
||||
clientUniverseDomain string
|
||||
creds *auth.Credentials
|
||||
base http.RoundTripper
|
||||
clientUniverseDomain string
|
||||
skipUniverseDomainValidation bool
|
||||
}
|
||||
|
||||
// getClientUniverseDomain returns the universe domain configured for the client.
|
||||
// The default value is "googleapis.com".
|
||||
// getClientUniverseDomain returns the default service domain for a given Cloud
|
||||
// universe, with the following precedence:
|
||||
//
|
||||
// 1. A non-empty option.WithUniverseDomain or similar client option.
|
||||
// 2. A non-empty environment variable GOOGLE_CLOUD_UNIVERSE_DOMAIN.
|
||||
// 3. The default value "googleapis.com".
|
||||
//
|
||||
// This is the universe domain configured for the client, which will be compared
|
||||
// to the universe domain that is separately configured for the credentials.
|
||||
func (t *authTransport) getClientUniverseDomain() string {
|
||||
if t.clientUniverseDomain == "" {
|
||||
return internal.DefaultUniverseDomain
|
||||
if t.clientUniverseDomain != "" {
|
||||
return t.clientUniverseDomain
|
||||
}
|
||||
return t.clientUniverseDomain
|
||||
if envUD := os.Getenv(internal.UniverseDomainEnvVar); envUD != "" {
|
||||
return envUD
|
||||
}
|
||||
return internal.DefaultUniverseDomain
|
||||
}
|
||||
|
||||
// RoundTrip authorizes and authenticates the request with an
|
||||
@@ -204,7 +218,7 @@ func (t *authTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||
if !t.skipUniverseDomainValidation && token.MetadataString("auth.google.tokenSource") != "compute-metadata" {
|
||||
credentialsUniverseDomain, err := t.creds.UniverseDomain(req.Context())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package compute
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
vmOnGCEOnce sync.Once
|
||||
vmOnGCE bool
|
||||
)
|
||||
|
||||
// OnComputeEngine returns whether the client is running on GCE.
|
||||
//
|
||||
// This is a copy of the gRPC internal googlecloud.OnGCE() func at:
|
||||
// https://github.com/grpc/grpc-go/blob/master/internal/googlecloud/googlecloud.go
|
||||
// The functionality is similar to the metadata.OnGCE() func at:
|
||||
// https://github.com/googleapis/google-cloud-go/blob/main/compute/metadata/metadata.go
|
||||
// The difference is that OnComputeEngine() does not perform HTTP or DNS check on the metadata server.
|
||||
// In particular, OnComputeEngine() will return false on Serverless.
|
||||
func OnComputeEngine() bool {
|
||||
vmOnGCEOnce.Do(func() {
|
||||
mf, err := manufacturer()
|
||||
if err != nil {
|
||||
log.Printf("Failed to read manufacturer, vmOnGCE=false: %v", err)
|
||||
return
|
||||
}
|
||||
vmOnGCE = isRunningOnGCE(mf, runtime.GOOS)
|
||||
})
|
||||
return vmOnGCE
|
||||
}
|
||||
|
||||
// isRunningOnGCE checks whether the local system, without doing a network request, is
|
||||
// running on GCP.
|
||||
func isRunningOnGCE(manufacturer []byte, goos string) bool {
|
||||
name := string(manufacturer)
|
||||
switch goos {
|
||||
case "linux":
|
||||
name = strings.TrimSpace(name)
|
||||
return name == "Google" || name == "Google Compute Engine"
|
||||
case "windows":
|
||||
name = strings.Replace(name, " ", "", -1)
|
||||
name = strings.Replace(name, "\n", "", -1)
|
||||
name = strings.Replace(name, "\r", "", -1)
|
||||
return name == "Google"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+8
-10
@@ -1,10 +1,13 @@
|
||||
// Copyright 2018, OpenCensus Authors
|
||||
//go:build !(linux || windows)
|
||||
// +build !linux,!windows
|
||||
|
||||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// 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,
|
||||
@@ -12,13 +15,8 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !go1.9
|
||||
// +build !go1.9
|
||||
package compute
|
||||
|
||||
package tag
|
||||
|
||||
import "context"
|
||||
|
||||
func do(ctx context.Context, f func(ctx context.Context)) {
|
||||
f(ctx)
|
||||
func manufacturer() ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
Generated
Vendored
+8
-11
@@ -1,9 +1,10 @@
|
||||
// Copyright 2023 The Prometheus Authors
|
||||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// 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,
|
||||
@@ -11,16 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build wasip1
|
||||
// +build wasip1
|
||||
package compute
|
||||
|
||||
package prometheus
|
||||
import "os"
|
||||
|
||||
func canCollectProcess() bool {
|
||||
return false
|
||||
}
|
||||
const linuxProductNameFile = "/sys/class/dmi/id/product_name"
|
||||
|
||||
func (*processCollector) processCollect(chan<- Metric) {
|
||||
// noop on this platform
|
||||
return
|
||||
func manufacturer() ([]byte, error) {
|
||||
return os.ReadFile(linuxProductNameFile)
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package compute
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
windowsCheckCommand = "powershell.exe"
|
||||
windowsCheckCommandArgs = "Get-WmiObject -Class Win32_BIOS"
|
||||
powershellOutputFilter = "Manufacturer"
|
||||
windowsManufacturerRegex = ":(.*)"
|
||||
)
|
||||
|
||||
func manufacturer() ([]byte, error) {
|
||||
cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
|
||||
if strings.HasPrefix(line, powershellOutputFilter) {
|
||||
re := regexp.MustCompile(windowsManufacturerRegex)
|
||||
name := re.FindString(line)
|
||||
name = strings.TrimLeft(name, ":")
|
||||
return []byte(name), nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("cannot determine the machine's manufacturer")
|
||||
}
|
||||
+19
-13
@@ -16,7 +16,7 @@ package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
@@ -38,8 +38,11 @@ const (
|
||||
// QuotaProjectEnvVar is the environment variable for setting the quota
|
||||
// project.
|
||||
QuotaProjectEnvVar = "GOOGLE_CLOUD_QUOTA_PROJECT"
|
||||
projectEnvVar = "GOOGLE_CLOUD_PROJECT"
|
||||
maxBodySize = 1 << 20
|
||||
// UniverseDomainEnvVar is the environment variable for setting the default
|
||||
// service domain for a given Cloud universe.
|
||||
UniverseDomainEnvVar = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"
|
||||
projectEnvVar = "GOOGLE_CLOUD_PROJECT"
|
||||
maxBodySize = 1 << 20
|
||||
|
||||
// DefaultUniverseDomain is the default value for universe domain.
|
||||
// Universe domain is the default service domain for a given Cloud universe.
|
||||
@@ -69,25 +72,27 @@ func DefaultClient() *http.Client {
|
||||
}
|
||||
|
||||
// ParseKey converts the binary contents of a private key file
|
||||
// to an *rsa.PrivateKey. It detects whether the private key is in a
|
||||
// to an crypto.Signer. It detects whether the private key is in a
|
||||
// PEM container or not. If so, it extracts the the private key
|
||||
// from PEM container before conversion. It only supports PEM
|
||||
// containers with no passphrase.
|
||||
func ParseKey(key []byte) (*rsa.PrivateKey, error) {
|
||||
func ParseKey(key []byte) (crypto.Signer, error) {
|
||||
block, _ := pem.Decode(key)
|
||||
if block != nil {
|
||||
key = block.Bytes
|
||||
}
|
||||
parsedKey, err := x509.ParsePKCS8PrivateKey(key)
|
||||
var parsedKey crypto.PrivateKey
|
||||
var err error
|
||||
parsedKey, err = x509.ParsePKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
parsedKey, err = x509.ParsePKCS1PrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("private key should be a PEM or plain PKCS1 or PKCS8: %w", err)
|
||||
}
|
||||
}
|
||||
parsed, ok := parsedKey.(*rsa.PrivateKey)
|
||||
parsed, ok := parsedKey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, errors.New("private key is invalid")
|
||||
return nil, errors.New("private key is not a signer")
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
@@ -176,6 +181,7 @@ func (p StaticProperty) GetProperty(context.Context) (string, error) {
|
||||
// ComputeUniverseDomainProvider fetches the credentials universe domain from
|
||||
// the google cloud metadata service.
|
||||
type ComputeUniverseDomainProvider struct {
|
||||
MetadataClient *metadata.Client
|
||||
universeDomainOnce sync.Once
|
||||
universeDomain string
|
||||
universeDomainErr error
|
||||
@@ -185,7 +191,7 @@ type ComputeUniverseDomainProvider struct {
|
||||
// metadata service.
|
||||
func (c *ComputeUniverseDomainProvider) GetProperty(ctx context.Context) (string, error) {
|
||||
c.universeDomainOnce.Do(func() {
|
||||
c.universeDomain, c.universeDomainErr = getMetadataUniverseDomain(ctx)
|
||||
c.universeDomain, c.universeDomainErr = getMetadataUniverseDomain(ctx, c.MetadataClient)
|
||||
})
|
||||
if c.universeDomainErr != nil {
|
||||
return "", c.universeDomainErr
|
||||
@@ -194,14 +200,14 @@ func (c *ComputeUniverseDomainProvider) GetProperty(ctx context.Context) (string
|
||||
}
|
||||
|
||||
// httpGetMetadataUniverseDomain is a package var for unit test substitution.
|
||||
var httpGetMetadataUniverseDomain = func(ctx context.Context) (string, error) {
|
||||
var httpGetMetadataUniverseDomain = func(ctx context.Context, client *metadata.Client) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
return metadata.GetWithContext(ctx, "universe/universe_domain")
|
||||
return client.GetWithContext(ctx, "universe/universe-domain")
|
||||
}
|
||||
|
||||
func getMetadataUniverseDomain(ctx context.Context) (string, error) {
|
||||
universeDomain, err := httpGetMetadataUniverseDomain(ctx)
|
||||
func getMetadataUniverseDomain(ctx context.Context, client *metadata.Client) (string, error) {
|
||||
universeDomain, err := httpGetMetadataUniverseDomain(ctx, client)
|
||||
if err == nil {
|
||||
return universeDomain, nil
|
||||
}
|
||||
|
||||
+2
-2
@@ -111,7 +111,7 @@ func (c *Claims) encode() (string, error) {
|
||||
}
|
||||
|
||||
// EncodeJWS encodes the data using the provided key as a JSON web signature.
|
||||
func EncodeJWS(header *Header, c *Claims, key *rsa.PrivateKey) (string, error) {
|
||||
func EncodeJWS(header *Header, c *Claims, signer crypto.Signer) (string, error) {
|
||||
head, err := header.encode()
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -123,7 +123,7 @@ func EncodeJWS(header *Header, c *Claims, key *rsa.PrivateKey) (string, error) {
|
||||
ss := fmt.Sprintf("%s.%s", head, claims)
|
||||
h := sha256.New()
|
||||
h.Write([]byte(ss))
|
||||
sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
|
||||
sig, err := signer.Sign(rand.Reader, h.Sum(nil), crypto.SHA256)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
+34
-22
@@ -20,6 +20,7 @@ import (
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"log"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -51,22 +52,19 @@ const (
|
||||
mtlsMDSKey = "/run/google-mds-mtls/client.key"
|
||||
)
|
||||
|
||||
var (
|
||||
errUniverseNotSupportedMTLS = errors.New("mTLS is not supported in any universe other than googleapis.com")
|
||||
)
|
||||
|
||||
// Options is a struct that is duplicated information from the individual
|
||||
// transport packages in order to avoid cyclic deps. It correlates 1:1 with
|
||||
// fields on httptransport.Options and grpctransport.Options.
|
||||
type Options struct {
|
||||
Endpoint string
|
||||
DefaultMTLSEndpoint string
|
||||
DefaultEndpointTemplate string
|
||||
DefaultMTLSEndpoint string
|
||||
ClientCertProvider cert.Provider
|
||||
Client *http.Client
|
||||
UniverseDomain string
|
||||
EnableDirectPath bool
|
||||
EnableDirectPathXds bool
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
// getUniverseDomain returns the default service domain for a given Cloud
|
||||
@@ -94,6 +92,16 @@ func (o *Options) defaultEndpoint() string {
|
||||
return strings.Replace(o.DefaultEndpointTemplate, universeDomainPlaceholder, o.getUniverseDomain(), 1)
|
||||
}
|
||||
|
||||
// defaultMTLSEndpoint returns the DefaultMTLSEndpointTemplate merged with the
|
||||
// universe domain if the DefaultMTLSEndpointTemplate is set, otherwise returns an
|
||||
// empty string.
|
||||
func (o *Options) defaultMTLSEndpoint() string {
|
||||
if o.DefaultMTLSEndpoint == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.Replace(o.DefaultMTLSEndpoint, universeDomainPlaceholder, o.getUniverseDomain(), 1)
|
||||
}
|
||||
|
||||
// mergedEndpoint merges a user-provided Endpoint of format host[:port] with the
|
||||
// default endpoint.
|
||||
func (o *Options) mergedEndpoint() (string, error) {
|
||||
@@ -133,7 +141,11 @@ func GetGRPCTransportCredsAndEndpoint(opts *Options) (credentials.TransportCrede
|
||||
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
|
||||
if err != nil {
|
||||
log.Printf("Loading MTLS MDS credentials failed: %v", err)
|
||||
return defaultTransportCreds, config.endpoint, nil
|
||||
if config.s2aAddress != "" {
|
||||
s2aAddr = config.s2aAddress
|
||||
} else {
|
||||
return defaultTransportCreds, config.endpoint, nil
|
||||
}
|
||||
}
|
||||
} else if config.s2aAddress != "" {
|
||||
s2aAddr = config.s2aAddress
|
||||
@@ -177,7 +189,11 @@ func GetHTTPTransportConfig(opts *Options) (cert.Provider, func(context.Context,
|
||||
transportCredsForS2A, err = loadMTLSMDSTransportCreds(mtlsMDSRoot, mtlsMDSKey)
|
||||
if err != nil {
|
||||
log.Printf("Loading MTLS MDS credentials failed: %v", err)
|
||||
return config.clientCertSource, nil, nil
|
||||
if config.s2aAddress != "" {
|
||||
s2aAddr = config.s2aAddress
|
||||
} else {
|
||||
return config.clientCertSource, nil, nil
|
||||
}
|
||||
}
|
||||
} else if config.s2aAddress != "" {
|
||||
s2aAddr = config.s2aAddress
|
||||
@@ -248,12 +264,9 @@ func getTransportConfig(opts *Options) (*transportConfig, error) {
|
||||
if !shouldUseS2A(clientCertSource, opts) {
|
||||
return &defaultTransportConfig, nil
|
||||
}
|
||||
if !opts.isUniverseDomainGDU() {
|
||||
return nil, errUniverseNotSupportedMTLS
|
||||
}
|
||||
|
||||
s2aAddress := GetS2AAddress()
|
||||
mtlsS2AAddress := GetMTLSS2AAddress()
|
||||
s2aAddress := GetS2AAddress(opts.Logger)
|
||||
mtlsS2AAddress := GetMTLSS2AAddress(opts.Logger)
|
||||
if s2aAddress == "" && mtlsS2AAddress == "" {
|
||||
return &defaultTransportConfig, nil
|
||||
}
|
||||
@@ -262,7 +275,7 @@ func getTransportConfig(opts *Options) (*transportConfig, error) {
|
||||
endpoint: endpoint,
|
||||
s2aAddress: s2aAddress,
|
||||
mtlsS2AAddress: mtlsS2AAddress,
|
||||
s2aMTLSEndpoint: opts.DefaultMTLSEndpoint,
|
||||
s2aMTLSEndpoint: opts.defaultMTLSEndpoint(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -308,24 +321,23 @@ type transportConfig struct {
|
||||
// getEndpoint returns the endpoint for the service, taking into account the
|
||||
// user-provided endpoint override "settings.Endpoint".
|
||||
//
|
||||
// If no endpoint override is specified, we will either return the default endpoint or
|
||||
// the default mTLS endpoint if a client certificate is available.
|
||||
// If no endpoint override is specified, we will either return the default
|
||||
// endpoint or the default mTLS endpoint if a client certificate is available.
|
||||
//
|
||||
// You can override the default endpoint choice (mtls vs. regular) by setting the
|
||||
// GOOGLE_API_USE_MTLS_ENDPOINT environment variable.
|
||||
// You can override the default endpoint choice (mTLS vs. regular) by setting
|
||||
// the GOOGLE_API_USE_MTLS_ENDPOINT environment variable.
|
||||
//
|
||||
// If the endpoint override is an address (host:port) rather than full base
|
||||
// URL (ex. https://...), then the user-provided address will be merged into
|
||||
// the default endpoint. For example, WithEndpoint("myhost:8000") and
|
||||
// DefaultEndpointTemplate("https://UNIVERSE_DOMAIN/bar/baz") will return "https://myhost:8080/bar/baz"
|
||||
// DefaultEndpointTemplate("https://UNIVERSE_DOMAIN/bar/baz") will return
|
||||
// "https://myhost:8080/bar/baz". Note that this does not apply to the mTLS
|
||||
// endpoint.
|
||||
func getEndpoint(opts *Options, clientCertSource cert.Provider) (string, error) {
|
||||
if opts.Endpoint == "" {
|
||||
mtlsMode := getMTLSMode()
|
||||
if mtlsMode == mTLSModeAlways || (clientCertSource != nil && mtlsMode == mTLSModeAuto) {
|
||||
if !opts.isUniverseDomainGDU() {
|
||||
return "", errUniverseNotSupportedMTLS
|
||||
}
|
||||
return opts.DefaultMTLSEndpoint, nil
|
||||
return opts.defaultMTLSEndpoint(), nil
|
||||
}
|
||||
return opts.defaultEndpoint(), nil
|
||||
}
|
||||
|
||||
+3
-5
@@ -16,7 +16,6 @@ package cert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
|
||||
"github.com/googleapis/enterprise-certificate-proxy/client"
|
||||
)
|
||||
@@ -37,10 +36,9 @@ type ecpSource struct {
|
||||
func NewEnterpriseCertificateProxyProvider(configFilePath string) (Provider, error) {
|
||||
key, err := client.Cred(configFilePath)
|
||||
if err != nil {
|
||||
if errors.Is(err, client.ErrCredUnavailable) {
|
||||
return nil, errSourceUnavailable
|
||||
}
|
||||
return nil, err
|
||||
// TODO(codyoss): once this is fixed upstream can handle this error a
|
||||
// little better here. But be safe for now and assume unavailable.
|
||||
return nil, errSourceUnavailable
|
||||
}
|
||||
|
||||
return (&ecpSource{
|
||||
|
||||
+1
-4
@@ -82,10 +82,7 @@ func (s *workloadSource) getClientCertificate(info *tls.CertificateRequestInfo)
|
||||
func getCertAndKeyFiles(configFilePath string) (string, string, error) {
|
||||
jsonFile, err := os.Open(configFilePath)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return "", "", errSourceUnavailable
|
||||
}
|
||||
return "", "", err
|
||||
return "", "", errSourceUnavailable
|
||||
}
|
||||
|
||||
byteValue, err := io.ReadAll(jsonFile)
|
||||
|
||||
+14
-10
@@ -19,6 +19,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -39,8 +40,8 @@ var (
|
||||
|
||||
// GetS2AAddress returns the S2A address to be reached via plaintext connection.
|
||||
// Returns empty string if not set or invalid.
|
||||
func GetS2AAddress() string {
|
||||
getMetadataMTLSAutoConfig()
|
||||
func GetS2AAddress(logger *slog.Logger) string {
|
||||
getMetadataMTLSAutoConfig(logger)
|
||||
if !mtlsConfiguration.valid() {
|
||||
return ""
|
||||
}
|
||||
@@ -49,8 +50,8 @@ func GetS2AAddress() string {
|
||||
|
||||
// GetMTLSS2AAddress returns the S2A address to be reached via MTLS connection.
|
||||
// Returns empty string if not set or invalid.
|
||||
func GetMTLSS2AAddress() string {
|
||||
getMetadataMTLSAutoConfig()
|
||||
func GetMTLSS2AAddress(logger *slog.Logger) string {
|
||||
getMetadataMTLSAutoConfig(logger)
|
||||
if !mtlsConfiguration.valid() {
|
||||
return ""
|
||||
}
|
||||
@@ -74,22 +75,25 @@ type s2aAddresses struct {
|
||||
MTLSAddress string `json:"mtls_address"`
|
||||
}
|
||||
|
||||
func getMetadataMTLSAutoConfig() {
|
||||
func getMetadataMTLSAutoConfig(logger *slog.Logger) {
|
||||
var err error
|
||||
mtlsOnce.Do(func() {
|
||||
mtlsConfiguration, err = queryConfig()
|
||||
mtlsConfiguration, err = queryConfig(logger)
|
||||
if err != nil {
|
||||
log.Printf("Getting MTLS config failed: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var httpGetMetadataMTLSConfig = func() (string, error) {
|
||||
return metadata.GetWithContext(context.Background(), configEndpointSuffix)
|
||||
var httpGetMetadataMTLSConfig = func(logger *slog.Logger) (string, error) {
|
||||
metadataClient := metadata.NewWithOptions(&metadata.Options{
|
||||
Logger: logger,
|
||||
})
|
||||
return metadataClient.GetWithContext(context.Background(), configEndpointSuffix)
|
||||
}
|
||||
|
||||
func queryConfig() (*mtlsConfig, error) {
|
||||
resp, err := httpGetMetadataMTLSConfig()
|
||||
func queryConfig(logger *slog.Logger) (*mtlsConfig, error) {
|
||||
resp, err := httpGetMetadataMTLSConfig(logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("querying MTLS config from MDS endpoint failed: %w", err)
|
||||
}
|
||||
|
||||
+1
@@ -49,6 +49,7 @@ func CloneDetectOptions(oldDo *credentials.DetectOptions) *credentials.DetectOpt
|
||||
// These fields are are pointer types that we just want to use exactly
|
||||
// as the user set, copy the ref
|
||||
Client: oldDo.Client,
|
||||
Logger: oldDo.Logger,
|
||||
AuthHandlerOptions: oldDo.AuthHandlerOptions,
|
||||
}
|
||||
|
||||
|
||||
+14
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [0.2.6](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.5...auth/oauth2adapt/v0.2.6) (2024-11-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth/oauth2adapt:** Copy map in tokenSourceAdapter.Token ([#11164](https://github.com/googleapis/google-cloud-go/issues/11164)) ([8cb0cbc](https://github.com/googleapis/google-cloud-go/commit/8cb0cbccdc32886dfb3af49fee04012937d114d2)), refs [#11161](https://github.com/googleapis/google-cloud-go/issues/11161)
|
||||
|
||||
## [0.2.5](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.4...auth/oauth2adapt/v0.2.5) (2024-10-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **auth/oauth2adapt:** Convert token metadata where possible ([#11062](https://github.com/googleapis/google-cloud-go/issues/11062)) ([34bf1c1](https://github.com/googleapis/google-cloud-go/commit/34bf1c164465d66745c0cfdf7cd10a8e2da92e52))
|
||||
|
||||
## [0.2.4](https://github.com/googleapis/google-cloud-go/compare/auth/oauth2adapt/v0.2.3...auth/oauth2adapt/v0.2.4) (2024-08-08)
|
||||
|
||||
|
||||
|
||||
+41
-5
@@ -26,6 +26,13 @@ import (
|
||||
"golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
const (
|
||||
oauth2TokenSourceKey = "oauth2.google.tokenSource"
|
||||
oauth2ServiceAccountKey = "oauth2.google.serviceAccount"
|
||||
authTokenSourceKey = "auth.google.tokenSource"
|
||||
authServiceAccountKey = "auth.google.serviceAccount"
|
||||
)
|
||||
|
||||
// TokenProviderFromTokenSource converts any [golang.org/x/oauth2.TokenSource]
|
||||
// into a [cloud.google.com/go/auth.TokenProvider].
|
||||
func TokenProviderFromTokenSource(ts oauth2.TokenSource) auth.TokenProvider {
|
||||
@@ -47,10 +54,21 @@ func (tp *tokenProviderAdapter) Token(context.Context) (*auth.Token, error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
// Preserve compute token metadata, for both types of tokens.
|
||||
metadata := map[string]interface{}{}
|
||||
if val, ok := tok.Extra(oauth2TokenSourceKey).(string); ok {
|
||||
metadata[authTokenSourceKey] = val
|
||||
metadata[oauth2TokenSourceKey] = val
|
||||
}
|
||||
if val, ok := tok.Extra(oauth2ServiceAccountKey).(string); ok {
|
||||
metadata[authServiceAccountKey] = val
|
||||
metadata[oauth2ServiceAccountKey] = val
|
||||
}
|
||||
return &auth.Token{
|
||||
Value: tok.AccessToken,
|
||||
Type: tok.Type(),
|
||||
Expiry: tok.Expiry,
|
||||
Value: tok.AccessToken,
|
||||
Type: tok.Type(),
|
||||
Expiry: tok.Expiry,
|
||||
Metadata: metadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -76,11 +94,29 @@ func (ts *tokenSourceAdapter) Token() (*oauth2.Token, error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &oauth2.Token{
|
||||
tok2 := &oauth2.Token{
|
||||
AccessToken: tok.Value,
|
||||
TokenType: tok.Type,
|
||||
Expiry: tok.Expiry,
|
||||
}, nil
|
||||
}
|
||||
// Preserve token metadata.
|
||||
m := tok.Metadata
|
||||
if m != nil {
|
||||
// Copy map to avoid concurrent map writes error (#11161).
|
||||
metadata := make(map[string]interface{}, len(m)+2)
|
||||
for k, v := range m {
|
||||
metadata[k] = v
|
||||
}
|
||||
// Append compute token metadata in converted form.
|
||||
if val, ok := metadata[authTokenSourceKey].(string); ok && val != "" {
|
||||
metadata[oauth2TokenSourceKey] = val
|
||||
}
|
||||
if val, ok := metadata[authServiceAccountKey].(string); ok && val != "" {
|
||||
metadata[oauth2ServiceAccountKey] = val
|
||||
}
|
||||
tok2 = tok2.WithExtra(metadata)
|
||||
}
|
||||
return tok2, nil
|
||||
}
|
||||
|
||||
// AuthCredentialsFromOauth2Credentials converts a [golang.org/x/oauth2/google.Credentials]
|
||||
|
||||
+14
@@ -20,6 +20,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -28,6 +29,7 @@ import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/auth/internal"
|
||||
"github.com/googleapis/gax-go/v2/internallog"
|
||||
)
|
||||
|
||||
// AuthorizationHandler is a 3-legged-OAuth helper that prompts the user for
|
||||
@@ -69,6 +71,11 @@ type Options3LO struct {
|
||||
// AuthHandlerOpts provides a set of options for doing a
|
||||
// 3-legged OAuth2 flow with a custom [AuthorizationHandler]. Optional.
|
||||
AuthHandlerOpts *AuthorizationHandlerOptions
|
||||
// Logger is used for debug logging. If provided, logging will be enabled
|
||||
// at the loggers configured level. By default logging is disabled unless
|
||||
// enabled by setting GOOGLE_SDK_GO_LOGGING_LEVEL in which case a default
|
||||
// logger will be used. Optional.
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (o *Options3LO) validate() error {
|
||||
@@ -96,6 +103,10 @@ func (o *Options3LO) validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Options3LO) logger() *slog.Logger {
|
||||
return internallog.New(o.Logger)
|
||||
}
|
||||
|
||||
// PKCEOptions holds parameters to support PKCE.
|
||||
type PKCEOptions struct {
|
||||
// Challenge is the un-padded, base64-url-encoded string of the encrypted code verifier.
|
||||
@@ -293,12 +304,15 @@ func fetchToken(ctx context.Context, o *Options3LO, v url.Values) (*Token, strin
|
||||
if o.AuthStyle == StyleInHeader {
|
||||
req.SetBasicAuth(url.QueryEscape(o.ClientID), url.QueryEscape(o.ClientSecret))
|
||||
}
|
||||
logger := o.logger()
|
||||
|
||||
logger.DebugContext(ctx, "3LO token request", "request", internallog.HTTPRequest(req, []byte(v.Encode())))
|
||||
// Make request
|
||||
resp, body, err := internal.DoRequest(o.client(), req)
|
||||
if err != nil {
|
||||
return nil, refreshToken, err
|
||||
}
|
||||
logger.DebugContext(ctx, "3LO token response", "response", internallog.HTTPResponse(resp, body))
|
||||
failureStatus := resp.StatusCode < 200 || resp.StatusCode > 299
|
||||
tokError := &Error{
|
||||
Response: resp,
|
||||
|
||||
+63
@@ -1,5 +1,68 @@
|
||||
# Changes
|
||||
|
||||
## [0.9.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.4...compute/metadata/v0.9.0) (2025-09-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compute/metadata:** Retry on HTTP 429 ([#12932](https://github.com/googleapis/google-cloud-go/issues/12932)) ([1e91f5c](https://github.com/googleapis/google-cloud-go/commit/1e91f5c07acacd38ecdd4ff3e83e092b745e0bc2))
|
||||
|
||||
## [0.8.4](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.3...compute/metadata/v0.8.4) (2025-09-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compute/metadata:** Set subClient for UseDefaultClient case ([#12911](https://github.com/googleapis/google-cloud-go/issues/12911)) ([9e2646b](https://github.com/googleapis/google-cloud-go/commit/9e2646b1821231183fd775bb107c062865eeaccd))
|
||||
|
||||
## [0.8.3](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.2...compute/metadata/v0.8.3) (2025-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compute/metadata:** Disable Client timeouts for subscription client ([#12910](https://github.com/googleapis/google-cloud-go/issues/12910)) ([187a58a](https://github.com/googleapis/google-cloud-go/commit/187a58a540494e1e8562b046325b8cad8cf7af4a))
|
||||
|
||||
## [0.8.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.1...compute/metadata/v0.8.2) (2025-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compute/metadata:** Racy test and uninitialized subClient ([#12892](https://github.com/googleapis/google-cloud-go/issues/12892)) ([4943ca2](https://github.com/googleapis/google-cloud-go/commit/4943ca2bf83908a23806247bc4252dfb440d09cc)), refs [#12888](https://github.com/googleapis/google-cloud-go/issues/12888)
|
||||
|
||||
## [0.8.1](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.8.0...compute/metadata/v0.8.1) (2025-09-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compute/metadata:** Use separate client for subscribe methods ([#12885](https://github.com/googleapis/google-cloud-go/issues/12885)) ([76b80f8](https://github.com/googleapis/google-cloud-go/commit/76b80f8df9bf9339d175407e8c15936fe1ac1c9c))
|
||||
|
||||
## [0.8.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.7.0...compute/metadata/v0.8.0) (2025-08-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compute/metadata:** Add Options.UseDefaultClient ([#12657](https://github.com/googleapis/google-cloud-go/issues/12657)) ([1a88209](https://github.com/googleapis/google-cloud-go/commit/1a8820900f20e038291c4bb2c5284a449196e81f)), refs [#11078](https://github.com/googleapis/google-cloud-go/issues/11078)
|
||||
|
||||
## [0.7.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.6.0...compute/metadata/v0.7.0) (2025-05-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compute/metadata:** Allow canceling GCE detection ([#11786](https://github.com/googleapis/google-cloud-go/issues/11786)) ([78100fe](https://github.com/googleapis/google-cloud-go/commit/78100fe7e28cd30f1e10b47191ac3c9839663b64))
|
||||
|
||||
## [0.6.0](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.2...compute/metadata/v0.6.0) (2024-12-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **compute/metadata:** Add debug logging ([#11078](https://github.com/googleapis/google-cloud-go/issues/11078)) ([a816814](https://github.com/googleapis/google-cloud-go/commit/a81681463906e4473570a2f426eb0dc2de64e53f))
|
||||
|
||||
## [0.5.2](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.1...compute/metadata/v0.5.2) (2024-09-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compute/metadata:** Close Response Body for failed request ([#10891](https://github.com/googleapis/google-cloud-go/issues/10891)) ([e91d45e](https://github.com/googleapis/google-cloud-go/commit/e91d45e4757a9e354114509ba9800085d9e0ff1f))
|
||||
|
||||
## [0.5.1](https://github.com/googleapis/google-cloud-go/compare/compute/metadata/v0.5.0...compute/metadata/v0.5.1) (2024-09-12)
|
||||
|
||||
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Code below this point is copied from github.com/googleapis/gax-go/v2/internallog
|
||||
// to avoid the dependency. The compute/metadata module is used by too many
|
||||
// non-client library modules that can't justify the dependency.
|
||||
|
||||
// The handler returned if logging is not enabled.
|
||||
type noOpHandler struct{}
|
||||
|
||||
func (h noOpHandler) Enabled(_ context.Context, _ slog.Level) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h noOpHandler) Handle(_ context.Context, _ slog.Record) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h noOpHandler) WithAttrs(_ []slog.Attr) slog.Handler {
|
||||
return h
|
||||
}
|
||||
|
||||
func (h noOpHandler) WithGroup(_ string) slog.Handler {
|
||||
return h
|
||||
}
|
||||
|
||||
// httpRequest returns a lazily evaluated [slog.LogValuer] for a
|
||||
// [http.Request] and the associated body.
|
||||
func httpRequest(req *http.Request, body []byte) slog.LogValuer {
|
||||
return &request{
|
||||
req: req,
|
||||
payload: body,
|
||||
}
|
||||
}
|
||||
|
||||
type request struct {
|
||||
req *http.Request
|
||||
payload []byte
|
||||
}
|
||||
|
||||
func (r *request) LogValue() slog.Value {
|
||||
if r == nil || r.req == nil {
|
||||
return slog.Value{}
|
||||
}
|
||||
var groupValueAttrs []slog.Attr
|
||||
groupValueAttrs = append(groupValueAttrs, slog.String("method", r.req.Method))
|
||||
groupValueAttrs = append(groupValueAttrs, slog.String("url", r.req.URL.String()))
|
||||
|
||||
var headerAttr []slog.Attr
|
||||
for k, val := range r.req.Header {
|
||||
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
|
||||
}
|
||||
if len(headerAttr) > 0 {
|
||||
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
|
||||
}
|
||||
|
||||
if len(r.payload) > 0 {
|
||||
if attr, ok := processPayload(r.payload); ok {
|
||||
groupValueAttrs = append(groupValueAttrs, attr)
|
||||
}
|
||||
}
|
||||
return slog.GroupValue(groupValueAttrs...)
|
||||
}
|
||||
|
||||
// httpResponse returns a lazily evaluated [slog.LogValuer] for a
|
||||
// [http.Response] and the associated body.
|
||||
func httpResponse(resp *http.Response, body []byte) slog.LogValuer {
|
||||
return &response{
|
||||
resp: resp,
|
||||
payload: body,
|
||||
}
|
||||
}
|
||||
|
||||
type response struct {
|
||||
resp *http.Response
|
||||
payload []byte
|
||||
}
|
||||
|
||||
func (r *response) LogValue() slog.Value {
|
||||
if r == nil {
|
||||
return slog.Value{}
|
||||
}
|
||||
var groupValueAttrs []slog.Attr
|
||||
groupValueAttrs = append(groupValueAttrs, slog.String("status", fmt.Sprint(r.resp.StatusCode)))
|
||||
|
||||
var headerAttr []slog.Attr
|
||||
for k, val := range r.resp.Header {
|
||||
headerAttr = append(headerAttr, slog.String(k, strings.Join(val, ",")))
|
||||
}
|
||||
if len(headerAttr) > 0 {
|
||||
groupValueAttrs = append(groupValueAttrs, slog.Any("headers", headerAttr))
|
||||
}
|
||||
|
||||
if len(r.payload) > 0 {
|
||||
if attr, ok := processPayload(r.payload); ok {
|
||||
groupValueAttrs = append(groupValueAttrs, attr)
|
||||
}
|
||||
}
|
||||
return slog.GroupValue(groupValueAttrs...)
|
||||
}
|
||||
|
||||
func processPayload(payload []byte) (slog.Attr, bool) {
|
||||
peekChar := payload[0]
|
||||
if peekChar == '{' {
|
||||
// JSON object
|
||||
var m map[string]any
|
||||
if err := json.Unmarshal(payload, &m); err == nil {
|
||||
return slog.Any("payload", m), true
|
||||
}
|
||||
} else if peekChar == '[' {
|
||||
// JSON array
|
||||
var m []any
|
||||
if err := json.Unmarshal(payload, &m); err == nil {
|
||||
return slog.Any("payload", m), true
|
||||
}
|
||||
} else {
|
||||
// Everything else
|
||||
buf := &bytes.Buffer{}
|
||||
if err := json.Compact(buf, payload); err != nil {
|
||||
// Write raw payload incase of error
|
||||
buf.Write(payload)
|
||||
}
|
||||
return slog.String("payload", buf.String()), true
|
||||
}
|
||||
return slog.Attr{}, false
|
||||
}
|
||||
+197
-96
@@ -22,8 +22,10 @@ package metadata // import "cloud.google.com/go/compute/metadata"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -60,19 +62,27 @@ var (
|
||||
instID = &cachedValue{k: "instance/id", trim: true}
|
||||
)
|
||||
|
||||
var defaultClient = &Client{hc: newDefaultHTTPClient()}
|
||||
var defaultClient = &Client{
|
||||
hc: newDefaultHTTPClient(true),
|
||||
subClient: newDefaultHTTPClient(false),
|
||||
logger: slog.New(noOpHandler{}),
|
||||
}
|
||||
|
||||
func newDefaultHTTPClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
IdleConnTimeout: 60 * time.Second,
|
||||
},
|
||||
Timeout: 5 * time.Second,
|
||||
func newDefaultHTTPClient(enableTimeouts bool) *http.Client {
|
||||
transport := &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 2 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
}
|
||||
c := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
if enableTimeouts {
|
||||
transport.IdleConnTimeout = 60 * time.Second
|
||||
c.Timeout = 5 * time.Second
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// NotDefinedError is returned when requested metadata is not defined.
|
||||
@@ -113,82 +123,20 @@ var (
|
||||
// NOTE: True returned from `OnGCE` does not guarantee that the metadata server
|
||||
// is accessible from this process and have all the metadata defined.
|
||||
func OnGCE() bool {
|
||||
onGCEOnce.Do(initOnGCE)
|
||||
return OnGCEWithContext(context.Background())
|
||||
}
|
||||
|
||||
// OnGCEWithContext reports whether this process is running on Google Compute Platforms.
|
||||
// This function's return value is memoized for better performance.
|
||||
// NOTE: True returned from `OnGCEWithContext` does not guarantee that the metadata server
|
||||
// is accessible from this process and have all the metadata defined.
|
||||
func OnGCEWithContext(ctx context.Context) bool {
|
||||
onGCEOnce.Do(func() {
|
||||
onGCE = defaultClient.OnGCEWithContext(ctx)
|
||||
})
|
||||
return onGCE
|
||||
}
|
||||
|
||||
func initOnGCE() {
|
||||
onGCE = testOnGCE()
|
||||
}
|
||||
|
||||
func testOnGCE() bool {
|
||||
// The user explicitly said they're on GCE, so trust them.
|
||||
if os.Getenv(metadataHostEnv) != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
resc := make(chan bool, 2)
|
||||
|
||||
// Try two strategies in parallel.
|
||||
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||
go func() {
|
||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
res, err := newDefaultHTTPClient().Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||
}()
|
||||
|
||||
go func() {
|
||||
resolver := &net.Resolver{}
|
||||
addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.")
|
||||
if err != nil || len(addrs) == 0 {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
resc <- strsContains(addrs, metadataIP)
|
||||
}()
|
||||
|
||||
tryHarder := systemInfoSuggestsGCE()
|
||||
if tryHarder {
|
||||
res := <-resc
|
||||
if res {
|
||||
// The first strategy succeeded, so let's use it.
|
||||
return true
|
||||
}
|
||||
// Wait for either the DNS or metadata server probe to
|
||||
// contradict the other one and say we are running on
|
||||
// GCE. Give it a lot of time to do so, since the system
|
||||
// info already suggests we're running on a GCE BIOS.
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case res = <-resc:
|
||||
return res
|
||||
case <-timer.C:
|
||||
// Too slow. Who knows what this system is.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// There's no hint from the system info that we're running on
|
||||
// GCE, so use the first probe's result as truth, whether it's
|
||||
// true or false. The goal here is to optimize for speed for
|
||||
// users who are NOT running on GCE. We can't assume that
|
||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||
// address is fast. Worst case this should return when the
|
||||
// metaClient's Transport.ResponseHeaderTimeout or
|
||||
// Transport.Dial.Timeout fires (in two seconds).
|
||||
return <-resc
|
||||
}
|
||||
|
||||
// Subscribe calls Client.SubscribeWithContext on the default client.
|
||||
//
|
||||
// Deprecated: Please use the context aware variant [SubscribeWithContext].
|
||||
@@ -409,21 +357,160 @@ func strsContains(ss []string, s string) bool {
|
||||
// A Client provides metadata.
|
||||
type Client struct {
|
||||
hc *http.Client
|
||||
// subClient by default is a HTTP Client that is only used for subscribe
|
||||
// methods that should not specify a timeout. If the user specifies a client
|
||||
// this with be the same as 'hc'.
|
||||
subClient *http.Client
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// Options for configuring a [Client].
|
||||
type Options struct {
|
||||
// Client is the HTTP client used to make requests. Optional.
|
||||
// If UseDefaultClient is true, this field is ignored.
|
||||
// If this field is nil, a new default http.Client will be created.
|
||||
Client *http.Client
|
||||
// Logger is used to log information about HTTP request and responses.
|
||||
// If not provided, nothing will be logged. Optional.
|
||||
Logger *slog.Logger
|
||||
// UseDefaultClient specifies that the client should use the same default
|
||||
// internal http.Client that is used in functions such as GetWithContext.
|
||||
// This is useful for sharing a single TCP connection pool across requests.
|
||||
// The difference vs GetWithContext is the ability to use this struct
|
||||
// to provide a custom logger. If this field is true, the Client
|
||||
// field is ignored.
|
||||
UseDefaultClient bool
|
||||
}
|
||||
|
||||
// NewClient returns a Client that can be used to fetch metadata.
|
||||
// Returns the client that uses the specified http.Client for HTTP requests.
|
||||
// If nil is specified, returns the default client.
|
||||
// If nil is specified, returns the default internal Client that is
|
||||
// also used in functions such as GetWithContext. This is useful for sharing
|
||||
// a single TCP connection pool across requests.
|
||||
func NewClient(c *http.Client) *Client {
|
||||
if c == nil {
|
||||
// Preserve original behavior for nil argument.
|
||||
return defaultClient
|
||||
}
|
||||
return &Client{hc: c}
|
||||
// Return a new client with a no-op logger for backward compatibility.
|
||||
return &Client{hc: c, subClient: c, logger: slog.New(noOpHandler{})}
|
||||
}
|
||||
|
||||
// NewWithOptions returns a Client that is configured with the provided Options.
|
||||
func NewWithOptions(opts *Options) *Client {
|
||||
// Preserve original behavior for nil opts.
|
||||
if opts == nil {
|
||||
return defaultClient
|
||||
}
|
||||
|
||||
// Handle explicit request for the internal default http.Client.
|
||||
if opts.UseDefaultClient {
|
||||
logger := opts.Logger
|
||||
if logger == nil {
|
||||
logger = slog.New(noOpHandler{})
|
||||
}
|
||||
return &Client{hc: defaultClient.hc, subClient: defaultClient.subClient, logger: logger}
|
||||
}
|
||||
|
||||
// Handle isolated client creation.
|
||||
client := opts.Client
|
||||
subClient := opts.Client
|
||||
if client == nil {
|
||||
client = newDefaultHTTPClient(true)
|
||||
subClient = newDefaultHTTPClient(false)
|
||||
}
|
||||
logger := opts.Logger
|
||||
if logger == nil {
|
||||
logger = slog.New(noOpHandler{})
|
||||
}
|
||||
return &Client{hc: client, subClient: subClient, logger: logger}
|
||||
}
|
||||
|
||||
// NOTE: metadataRequestStrategy is assigned to a variable for test stubbing purposes.
|
||||
var metadataRequestStrategy = func(ctx context.Context, httpClient *http.Client, resc chan bool) {
|
||||
req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
res, err := httpClient.Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
resc <- res.Header.Get("Metadata-Flavor") == "Google"
|
||||
}
|
||||
|
||||
// NOTE: dnsRequestStrategy is assigned to a variable for test stubbing purposes.
|
||||
var dnsRequestStrategy = func(ctx context.Context, resc chan bool) {
|
||||
resolver := &net.Resolver{}
|
||||
addrs, err := resolver.LookupHost(ctx, "metadata.google.internal.")
|
||||
if err != nil || len(addrs) == 0 {
|
||||
resc <- false
|
||||
return
|
||||
}
|
||||
resc <- strsContains(addrs, metadataIP)
|
||||
}
|
||||
|
||||
// OnGCEWithContext reports whether this process is running on Google Compute Platforms.
|
||||
// NOTE: True returned from `OnGCEWithContext` does not guarantee that the metadata server
|
||||
// is accessible from this process and have all the metadata defined.
|
||||
func (c *Client) OnGCEWithContext(ctx context.Context) bool {
|
||||
// The user explicitly said they're on GCE, so trust them.
|
||||
if os.Getenv(metadataHostEnv) != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
resc := make(chan bool, 2)
|
||||
|
||||
// Try two strategies in parallel.
|
||||
// See https://github.com/googleapis/google-cloud-go/issues/194
|
||||
go metadataRequestStrategy(ctx, c.hc, resc)
|
||||
go dnsRequestStrategy(ctx, resc)
|
||||
|
||||
tryHarder := systemInfoSuggestsGCE()
|
||||
if tryHarder {
|
||||
res := <-resc
|
||||
if res {
|
||||
// The first strategy succeeded, so let's use it.
|
||||
return true
|
||||
}
|
||||
|
||||
// Wait for either the DNS or metadata server probe to
|
||||
// contradict the other one and say we are running on
|
||||
// GCE. Give it a lot of time to do so, since the system
|
||||
// info already suggests we're running on a GCE BIOS.
|
||||
// Ensure cancellations from the calling context are respected.
|
||||
waitContext, cancelWait := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancelWait()
|
||||
select {
|
||||
case res = <-resc:
|
||||
return res
|
||||
case <-waitContext.Done():
|
||||
// Too slow. Who knows what this system is.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// There's no hint from the system info that we're running on
|
||||
// GCE, so use the first probe's result as truth, whether it's
|
||||
// true or false. The goal here is to optimize for speed for
|
||||
// users who are NOT running on GCE. We can't assume that
|
||||
// either a DNS lookup or an HTTP request to a blackholed IP
|
||||
// address is fast. Worst case this should return when the
|
||||
// metaClient's Transport.ResponseHeaderTimeout or
|
||||
// Transport.Dial.Timeout fires (in two seconds).
|
||||
return <-resc
|
||||
}
|
||||
|
||||
// getETag returns a value from the metadata service as well as the associated ETag.
|
||||
// This func is otherwise equivalent to Get.
|
||||
func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string, err error) {
|
||||
return c.getETagWithSubClient(ctx, suffix, false)
|
||||
}
|
||||
|
||||
func (c *Client) getETagWithSubClient(ctx context.Context, suffix string, enableSubClient bool) (value, etag string, err error) {
|
||||
// Using a fixed IP makes it very difficult to spoof the metadata service in
|
||||
// a container, which is an important use-case for local testing of cloud
|
||||
// deployments. To enable spoofing of the metadata service, the environment
|
||||
@@ -448,14 +535,30 @@ func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
var res *http.Response
|
||||
var reqErr error
|
||||
var body []byte
|
||||
retryer := newRetryer()
|
||||
hc := c.hc
|
||||
if enableSubClient {
|
||||
hc = c.subClient
|
||||
}
|
||||
for {
|
||||
res, reqErr = c.hc.Do(req)
|
||||
c.logger.DebugContext(ctx, "metadata request", "request", httpRequest(req, nil))
|
||||
res, reqErr = hc.Do(req)
|
||||
var code int
|
||||
if res != nil {
|
||||
code = res.StatusCode
|
||||
body, err = io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close()
|
||||
return "", "", err
|
||||
}
|
||||
c.logger.DebugContext(ctx, "metadata response", "response", httpResponse(res, body))
|
||||
res.Body.Close()
|
||||
}
|
||||
if delay, shouldRetry := retryer.Retry(code, reqErr); shouldRetry {
|
||||
if res != nil && res.Body != nil {
|
||||
res.Body.Close()
|
||||
}
|
||||
if err := sleep(ctx, delay); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -466,18 +569,13 @@ func (c *Client) getETag(ctx context.Context, suffix string) (value, etag string
|
||||
if reqErr != nil {
|
||||
return "", "", reqErr
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return "", "", NotDefinedError(suffix)
|
||||
}
|
||||
all, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return "", "", &Error{Code: res.StatusCode, Message: string(all)}
|
||||
return "", "", &Error{Code: res.StatusCode, Message: string(body)}
|
||||
}
|
||||
return string(all), res.Header.Get("Etag"), nil
|
||||
return string(body), res.Header.Get("Etag"), nil
|
||||
}
|
||||
|
||||
// Get returns a value from the metadata service.
|
||||
@@ -791,7 +889,7 @@ func (c *Client) SubscribeWithContext(ctx context.Context, suffix string, fn fun
|
||||
const failedSubscribeSleep = time.Second * 5
|
||||
|
||||
// First check to see if the metadata value exists at all.
|
||||
val, lastETag, err := c.getETag(ctx, suffix)
|
||||
val, lastETag, err := c.getETagWithSubClient(ctx, suffix, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -807,8 +905,11 @@ func (c *Client) SubscribeWithContext(ctx context.Context, suffix string, fn fun
|
||||
suffix += "?wait_for_change=true&last_etag="
|
||||
}
|
||||
for {
|
||||
val, etag, err := c.getETag(ctx, suffix+url.QueryEscape(lastETag))
|
||||
val, etag, err := c.getETagWithSubClient(ctx, suffix+url.QueryEscape(lastETag), true)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
if _, deleted := err.(NotDefinedError); !deleted {
|
||||
time.Sleep(failedSubscribeSleep)
|
||||
continue // Retry on other errors.
|
||||
|
||||
+3
@@ -95,6 +95,9 @@ func shouldRetry(status int, err error) bool {
|
||||
if 500 <= status && status <= 599 {
|
||||
return true
|
||||
}
|
||||
if status == http.StatusTooManyRequests {
|
||||
return true
|
||||
}
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return true
|
||||
}
|
||||
|
||||
+3
-1
@@ -20,7 +20,9 @@ package metadata
|
||||
// doing network requests) suggests that we're running on GCE. If this
|
||||
// returns true, testOnGCE tries a bit harder to reach its metadata
|
||||
// server.
|
||||
func systemInfoSuggestsGCE() bool {
|
||||
//
|
||||
// NOTE: systemInfoSuggestsGCE is assigned to a varible for test stubbing purposes.
|
||||
var systemInfoSuggestsGCE = func() bool {
|
||||
// We don't currently have checks for other GOOS
|
||||
return false
|
||||
}
|
||||
+3
-1
@@ -21,8 +21,10 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func systemInfoSuggestsGCE() bool {
|
||||
// NOTE: systemInfoSuggestsGCE is assigned to a varible for test stubbing purposes.
|
||||
var systemInfoSuggestsGCE = func() bool {
|
||||
b, _ := os.ReadFile("/sys/class/dmi/id/product_name")
|
||||
|
||||
name := strings.TrimSpace(string(b))
|
||||
return name == "Google" || name == "Google Compute Engine"
|
||||
}
|
||||
+2
-1
@@ -22,7 +22,8 @@ import (
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
func systemInfoSuggestsGCE() bool {
|
||||
// NOTE: systemInfoSuggestsGCE is assigned to a varible for test stubbing purposes.
|
||||
var systemInfoSuggestsGCE = func() bool {
|
||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\HardwareConfig\Current`, registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
return false
|
||||
|
||||
+8
@@ -1,6 +1,14 @@
|
||||
# Changes
|
||||
|
||||
|
||||
## [1.2.2](https://github.com/googleapis/google-cloud-go/compare/iam/v1.2.1...iam/v1.2.2) (2024-10-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **iam:** Update google.golang.org/api to v0.203.0 ([8bb87d5](https://github.com/googleapis/google-cloud-go/commit/8bb87d56af1cba736e0fe243979723e747e5e11e))
|
||||
* **iam:** WARNING: On approximately Dec 1, 2024, an update to Protobuf will change service registration function signatures to use an interface instead of a concrete type in generated .pb.go files. This change is expected to affect very few if any users of this client library. For more information, see https://togithub.com/googleapis/google-cloud-go/issues/11020. ([8bb87d5](https://github.com/googleapis/google-cloud-go/commit/8bb87d56af1cba736e0fe243979723e747e5e11e))
|
||||
|
||||
## [1.2.1](https://github.com/googleapis/google-cloud-go/compare/iam/v1.2.0...iam/v1.2.1) (2024-09-12)
|
||||
|
||||
|
||||
|
||||
+5
-6
@@ -363,16 +363,15 @@ var file_google_iam_v1_iam_policy_proto_rawDesc = []byte{
|
||||
0x65, 0x3d, 0x2a, 0x2a, 0x7d, 0x3a, 0x74, 0x65, 0x73, 0x74, 0x49, 0x61, 0x6d, 0x50, 0x65, 0x72,
|
||||
0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x1e, 0xca, 0x41, 0x1b, 0x69, 0x61, 0x6d,
|
||||
0x2d, 0x6d, 0x65, 0x74, 0x61, 0x2d, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x42, 0x7f, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x42, 0x7c, 0x0a, 0x11, 0x63, 0x6f, 0x6d, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x69, 0x61, 0x6d, 0x2e, 0x76, 0x31, 0x42, 0x0e, 0x49,
|
||||
0x61, 0x6d, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
|
||||
0x29, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x67, 0x6f, 0x2f, 0x69, 0x61, 0x6d, 0x2f, 0x61, 0x70, 0x69, 0x76, 0x31, 0x2f, 0x69,
|
||||
0x61, 0x6d, 0x70, 0x62, 0x3b, 0x69, 0x61, 0x6d, 0x70, 0x62, 0xf8, 0x01, 0x01, 0xaa, 0x02, 0x13,
|
||||
0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d,
|
||||
0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f,
|
||||
0x75, 0x64, 0x5c, 0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x61, 0x6d, 0x70, 0x62, 0x3b, 0x69, 0x61, 0x6d, 0x70, 0x62, 0xaa, 0x02, 0x13, 0x47, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x49, 0x61, 0x6d, 0x2e, 0x56, 0x31,
|
||||
0xca, 0x02, 0x13, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c,
|
||||
0x49, 0x61, 0x6d, 0x5c, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
+52
-2
@@ -179,6 +179,16 @@
|
||||
"release_level": "stable",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/apihub/apiv1": {
|
||||
"api_shortname": "apihub",
|
||||
"distribution_name": "cloud.google.com/go/apihub/apiv1",
|
||||
"description": "API hub API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/apihub/latest/apiv1",
|
||||
"release_level": "preview",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/apikeys/apiv2": {
|
||||
"api_shortname": "apikeys",
|
||||
"distribution_name": "cloud.google.com/go/apikeys/apiv2",
|
||||
@@ -559,6 +569,16 @@
|
||||
"release_level": "stable",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/bigquery/storage/apiv1alpha": {
|
||||
"api_shortname": "bigquerystorage",
|
||||
"distribution_name": "cloud.google.com/go/bigquery/storage/apiv1alpha",
|
||||
"description": "BigQuery Storage API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/bigquery/latest/storage/apiv1alpha",
|
||||
"release_level": "preview",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/bigquery/storage/apiv1beta1": {
|
||||
"api_shortname": "bigquerystorage",
|
||||
"distribution_name": "cloud.google.com/go/bigquery/storage/apiv1beta1",
|
||||
@@ -1009,6 +1029,16 @@
|
||||
"release_level": "stable",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/datastore/apiv1": {
|
||||
"api_shortname": "datastore",
|
||||
"distribution_name": "cloud.google.com/go/datastore/apiv1",
|
||||
"description": "Cloud Datastore API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/datastore/latest/apiv1",
|
||||
"release_level": "stable",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/datastream/apiv1": {
|
||||
"api_shortname": "datastream",
|
||||
"distribution_name": "cloud.google.com/go/datastream/apiv1",
|
||||
@@ -1329,6 +1359,16 @@
|
||||
"release_level": "stable",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/gkeconnect/gateway/apiv1": {
|
||||
"api_shortname": "connectgateway",
|
||||
"distribution_name": "cloud.google.com/go/gkeconnect/gateway/apiv1",
|
||||
"description": "Connect Gateway API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkeconnect/latest/gateway/apiv1",
|
||||
"release_level": "preview",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/gkeconnect/gateway/apiv1beta1": {
|
||||
"api_shortname": "connectgateway",
|
||||
"distribution_name": "cloud.google.com/go/gkeconnect/gateway/apiv1beta1",
|
||||
@@ -1352,7 +1392,7 @@
|
||||
"cloud.google.com/go/gkemulticloud/apiv1": {
|
||||
"api_shortname": "gkemulticloud",
|
||||
"distribution_name": "cloud.google.com/go/gkemulticloud/apiv1",
|
||||
"description": "Anthos Multi-Cloud API",
|
||||
"description": "GKE Multi-Cloud API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/gkemulticloud/latest/apiv1",
|
||||
@@ -1552,7 +1592,7 @@
|
||||
"cloud.google.com/go/managedkafka/apiv1": {
|
||||
"api_shortname": "managedkafka",
|
||||
"distribution_name": "cloud.google.com/go/managedkafka/apiv1",
|
||||
"description": "Apache Kafka for BigQuery API",
|
||||
"description": "Managed Service for Apache Kafka API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/managedkafka/latest/apiv1",
|
||||
@@ -1569,6 +1609,16 @@
|
||||
"release_level": "stable",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/maps/areainsights/apiv1": {
|
||||
"api_shortname": "areainsights",
|
||||
"distribution_name": "cloud.google.com/go/maps/areainsights/apiv1",
|
||||
"description": "Places Insights API",
|
||||
"language": "go",
|
||||
"client_library_type": "generated",
|
||||
"client_documentation": "https://cloud.google.com/go/docs/reference/cloud.google.com/go/maps/latest/areainsights/apiv1",
|
||||
"release_level": "preview",
|
||||
"library_type": "GAPIC_AUTO"
|
||||
},
|
||||
"cloud.google.com/go/maps/fleetengine/apiv1": {
|
||||
"api_shortname": "fleetengine",
|
||||
"distribution_name": "cloud.google.com/go/maps/fleetengine/apiv1",
|
||||
|
||||
+1
-1
@@ -15,4 +15,4 @@
|
||||
package internal
|
||||
|
||||
// Version is the current tagged release of the library.
|
||||
const Version = "1.21.0"
|
||||
const Version = "1.21.2"
|
||||
+89
@@ -1,6 +1,95 @@
|
||||
# Changes
|
||||
|
||||
|
||||
## [1.50.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.49.0...storage/v1.50.0) (2025-01-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **storage/internal:** Add new appendable Object to BidiWrite API ([2e4feb9](https://github.com/googleapis/google-cloud-go/commit/2e4feb938ce9ab023c8aa6bd1dbdf36fe589213a))
|
||||
* **storage/internal:** Add new preview BidiReadObject API ([2e4feb9](https://github.com/googleapis/google-cloud-go/commit/2e4feb938ce9ab023c8aa6bd1dbdf36fe589213a))
|
||||
* **storage:** Add support for gRPC bi-directional multi-range reads. This API is in private preview and not generally and is not yet available for general use. ([#11377](https://github.com/googleapis/google-cloud-go/issues/11377)) ([b4d86a5](https://github.com/googleapis/google-cloud-go/commit/b4d86a52bd319a602115cdb710a743c71494a88b))
|
||||
* **storage:** Add support for ReadHandle, a gRPC feature that allows for accelerated resumption of streams when one is interrupted. ReadHandle requires the bi-directional read API, which is in private preview and is not yet available for general use. ([#11377](https://github.com/googleapis/google-cloud-go/issues/11377)) ([b4d86a5](https://github.com/googleapis/google-cloud-go/commit/b4d86a52bd319a602115cdb710a743c71494a88b))
|
||||
* **storage:** Support appendable semantics for writes in gRPC. This API is in preview. ([#11377](https://github.com/googleapis/google-cloud-go/issues/11377)) ([b4d86a5](https://github.com/googleapis/google-cloud-go/commit/b4d86a52bd319a602115cdb710a743c71494a88b))
|
||||
* **storage:** Refactor gRPC writer flow ([#11377](https://github.com/googleapis/google-cloud-go/issues/11377)) ([b4d86a5](https://github.com/googleapis/google-cloud-go/commit/b4d86a52bd319a602115cdb710a743c71494a88b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **storage:** Add mutex around uses of mrd variables ([#11405](https://github.com/googleapis/google-cloud-go/issues/11405)) ([54bfc32](https://github.com/googleapis/google-cloud-go/commit/54bfc32db7a0ff40a493de4d466f21ad624de04e))
|
||||
* **storage:** Return the appropriate error for method not supported ([#11416](https://github.com/googleapis/google-cloud-go/issues/11416)) ([56d704e](https://github.com/googleapis/google-cloud-go/commit/56d704e3037840aeb87b22cc83f2b6088c79bcee))
|
||||
|
||||
|
||||
### Documentation
|
||||
|
||||
* **storage/internal:** Add IAM information to RPC comments for reference documentation ([2e4feb9](https://github.com/googleapis/google-cloud-go/commit/2e4feb938ce9ab023c8aa6bd1dbdf36fe589213a))
|
||||
* **storage:** Add preview comment to NewMultiRangeDownloader ([#11420](https://github.com/googleapis/google-cloud-go/issues/11420)) ([4ec1d66](https://github.com/googleapis/google-cloud-go/commit/4ec1d66ee180e800606568e8693a282645ec7369))
|
||||
|
||||
## [1.49.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.48.0...storage/v1.49.0) (2024-12-21)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **storage/internal:** Add finalize_time field in Object metadata ([46fc993](https://github.com/googleapis/google-cloud-go/commit/46fc993a3195203a230e2831bee456baaa9f7b1c))
|
||||
* **storage/internal:** Add MoveObject RPC ([46fc993](https://github.com/googleapis/google-cloud-go/commit/46fc993a3195203a230e2831bee456baaa9f7b1c))
|
||||
* **storage:** Add ObjectHandle.Move method ([#11302](https://github.com/googleapis/google-cloud-go/issues/11302)) ([a3cb8c4](https://github.com/googleapis/google-cloud-go/commit/a3cb8c4fc48883b54d4e830ae5f5ef4f1a3b8ca3))
|
||||
* **storage:** Return file metadata on read ([#11212](https://github.com/googleapis/google-cloud-go/issues/11212)) ([d49263b](https://github.com/googleapis/google-cloud-go/commit/d49263b2ab614cad801e26b4a169eafe08d4a2a0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **storage/dataflux:** Address deadlock when reading from ranges ([#11303](https://github.com/googleapis/google-cloud-go/issues/11303)) ([32cbf56](https://github.com/googleapis/google-cloud-go/commit/32cbf561590541eb0387787bf729be6ddf68e4ee))
|
||||
* **storage:** Disable allow non-default credentials flag ([#11337](https://github.com/googleapis/google-cloud-go/issues/11337)) ([145ddf4](https://github.com/googleapis/google-cloud-go/commit/145ddf4f6123d9561856d2b6adeefdfae462b3f7))
|
||||
* **storage:** Monitored resource detection ([#11197](https://github.com/googleapis/google-cloud-go/issues/11197)) ([911bcd8](https://github.com/googleapis/google-cloud-go/commit/911bcd8b1816256482bd52e85da7eaf00c315293))
|
||||
* **storage:** Update golang.org/x/net to v0.33.0 ([e9b0b69](https://github.com/googleapis/google-cloud-go/commit/e9b0b69644ea5b276cacff0a707e8a5e87efafc9))
|
||||
|
||||
## [1.48.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.47.0...storage/v1.48.0) (2024-12-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **storage/dataflux:** Run worksteal listing parallel to sequential listing ([#10966](https://github.com/googleapis/google-cloud-go/issues/10966)) ([3005f5a](https://github.com/googleapis/google-cloud-go/commit/3005f5a86c18254e569b8b1782bf014aa62f33cc))
|
||||
* **storage:** Add Writer.ChunkTransferTimeout ([#11111](https://github.com/googleapis/google-cloud-go/issues/11111)) ([fd1db20](https://github.com/googleapis/google-cloud-go/commit/fd1db203d0de898891b9920aacb141ea39228609))
|
||||
* **storage:** Allow non default service account ([#11137](https://github.com/googleapis/google-cloud-go/issues/11137)) ([19f01c3](https://github.com/googleapis/google-cloud-go/commit/19f01c3c48ed1272c8fc0af9e5f69646cb662808))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **storage:** Add backoff to gRPC write retries ([#11200](https://github.com/googleapis/google-cloud-go/issues/11200)) ([a7db927](https://github.com/googleapis/google-cloud-go/commit/a7db927da9cf4c6cf242a5db83e44a16d75a8291))
|
||||
* **storage:** Correct direct connectivity check ([#11152](https://github.com/googleapis/google-cloud-go/issues/11152)) ([a75c8b0](https://github.com/googleapis/google-cloud-go/commit/a75c8b0f72c38d9a85c908715c3e37eb5cffb131))
|
||||
* **storage:** Disable soft delete policy using 0 retentionDurationSeconds ([#11226](https://github.com/googleapis/google-cloud-go/issues/11226)) ([f087721](https://github.com/googleapis/google-cloud-go/commit/f087721b7b20ad28ded1d0a84756a8bbaa2bb95a))
|
||||
* **storage:** Retry SignBlob call for URL signing ([#11154](https://github.com/googleapis/google-cloud-go/issues/11154)) ([f198452](https://github.com/googleapis/google-cloud-go/commit/f198452fd2b29e779e9080ba79d7e873eb0c32ef))
|
||||
|
||||
## [1.47.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.46.0...storage/v1.47.0) (2024-11-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **storage:** Introduce dp detector based on grpc metrics ([#11100](https://github.com/googleapis/google-cloud-go/issues/11100)) ([60c2323](https://github.com/googleapis/google-cloud-go/commit/60c2323102b623e042fc508e2b1bb830a03f9577))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **storage:** Bump auth dep ([#11135](https://github.com/googleapis/google-cloud-go/issues/11135)) ([9620a51](https://github.com/googleapis/google-cloud-go/commit/9620a51b2c6904d8d93e124494bc297fb98553d2))
|
||||
|
||||
## [1.46.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.45.0...storage/v1.46.0) (2024-10-31)
|
||||
|
||||
### Features
|
||||
|
||||
* **storage:** Add grpc metrics experimental options ([#10984](https://github.com/googleapis/google-cloud-go/issues/10984)) ([5b7397b](https://github.com/googleapis/google-cloud-go/commit/5b7397b169176f030049e1511859a883422c774e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **storage:** Skip only specific transport tests. ([#11016](https://github.com/googleapis/google-cloud-go/issues/11016)) ([d40fbff](https://github.com/googleapis/google-cloud-go/commit/d40fbff9c1984aeed0224a4ac93eb95c5af17126))
|
||||
* **storage:** Update google.golang.org/api to v0.203.0 ([8bb87d5](https://github.com/googleapis/google-cloud-go/commit/8bb87d56af1cba736e0fe243979723e747e5e11e))
|
||||
* **storage:** WARNING: On approximately Dec 1, 2024, an update to Protobuf will change service registration function signatures to use an interface instead of a concrete type in generated .pb.go files. This change is expected to affect very few if any users of this client library. For more information, see https://togithub.com/googleapis/google-cloud-go/issues/11020. ([2b8ca4b](https://github.com/googleapis/google-cloud-go/commit/2b8ca4b4127ce3025c7a21cc7247510e07cc5625))
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* **storage/internal:** Remove notification, service account, and hmac RPCS. These API have been migrated to Storage Control and are available via the JSON API. ([#11008](https://github.com/googleapis/google-cloud-go/issues/11008)) ([e0759f4](https://github.com/googleapis/google-cloud-go/commit/e0759f46639b4c542e5b49e4dc81340d8e123370))
|
||||
|
||||
## [1.45.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.44.0...storage/v1.45.0) (2024-10-17)
|
||||
|
||||
|
||||
|
||||
+12
-7
@@ -326,11 +326,14 @@ func (b *BucketHandle) defaultSignBytesFunc(email string) func([]byte) ([]byte,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create iamcredentials client: %w", err)
|
||||
}
|
||||
|
||||
resp, err := svc.Projects.ServiceAccounts.SignBlob(fmt.Sprintf("projects/-/serviceAccounts/%s", email), &iamcredentials.SignBlobRequest{
|
||||
Payload: base64.StdEncoding.EncodeToString(in),
|
||||
}).Do()
|
||||
if err != nil {
|
||||
// Do the SignBlob call with a retry for transient errors.
|
||||
var resp *iamcredentials.SignBlobResponse
|
||||
if err := run(ctx, func(ctx context.Context) error {
|
||||
resp, err = svc.Projects.ServiceAccounts.SignBlob(fmt.Sprintf("projects/-/serviceAccounts/%s", email), &iamcredentials.SignBlobRequest{
|
||||
Payload: base64.StdEncoding.EncodeToString(in),
|
||||
}).Do()
|
||||
return err
|
||||
}, b.retry, true); err != nil {
|
||||
return nil, fmt.Errorf("unable to sign bytes: %w", err)
|
||||
}
|
||||
out, err := base64.StdEncoding.DecodeString(resp.SignedBlob)
|
||||
@@ -1338,8 +1341,10 @@ func (ua *BucketAttrsToUpdate) toRawBucket() *raw.Bucket {
|
||||
}
|
||||
if ua.SoftDeletePolicy != nil {
|
||||
if ua.SoftDeletePolicy.RetentionDuration == 0 {
|
||||
rb.NullFields = append(rb.NullFields, "SoftDeletePolicy")
|
||||
rb.SoftDeletePolicy = nil
|
||||
rb.SoftDeletePolicy = &raw.BucketSoftDeletePolicy{
|
||||
RetentionDurationSeconds: 0,
|
||||
ForceSendFields: []string{"RetentionDurationSeconds"},
|
||||
}
|
||||
} else {
|
||||
rb.SoftDeletePolicy = ua.SoftDeletePolicy.toRawSoftDeletePolicy()
|
||||
}
|
||||
|
||||
+25
-1
@@ -62,6 +62,7 @@ type storageClient interface {
|
||||
GetObject(ctx context.Context, params *getObjectParams, opts ...storageOption) (*ObjectAttrs, error)
|
||||
UpdateObject(ctx context.Context, params *updateObjectParams, opts ...storageOption) (*ObjectAttrs, error)
|
||||
RestoreObject(ctx context.Context, params *restoreObjectParams, opts ...storageOption) (*ObjectAttrs, error)
|
||||
MoveObject(ctx context.Context, params *moveObjectParams, opts ...storageOption) (*ObjectAttrs, error)
|
||||
|
||||
// Default Object ACL methods.
|
||||
|
||||
@@ -107,6 +108,8 @@ type storageClient interface {
|
||||
ListNotifications(ctx context.Context, bucket string, opts ...storageOption) (map[string]*Notification, error)
|
||||
CreateNotification(ctx context.Context, bucket string, n *Notification, opts ...storageOption) (*Notification, error)
|
||||
DeleteNotification(ctx context.Context, bucket string, id string, opts ...storageOption) error
|
||||
|
||||
NewMultiRangeDownloader(ctx context.Context, params *newMultiRangeDownloaderParams, opts ...storageOption) (*MultiRangeDownloader, error)
|
||||
}
|
||||
|
||||
// settings contains transport-agnostic configuration for API calls made via
|
||||
@@ -237,7 +240,8 @@ type openWriterParams struct {
|
||||
chunkSize int
|
||||
// chunkRetryDeadline - see `Writer.ChunkRetryDeadline`.
|
||||
// Optional.
|
||||
chunkRetryDeadline time.Duration
|
||||
chunkRetryDeadline time.Duration
|
||||
chunkTransferTimeout time.Duration
|
||||
|
||||
// Object/request properties
|
||||
|
||||
@@ -259,6 +263,9 @@ type openWriterParams struct {
|
||||
// sendCRC32C - see `Writer.SendCRC32C`.
|
||||
// Optional.
|
||||
sendCRC32C bool
|
||||
// append - Write with appendable object semantics.
|
||||
// Optional.
|
||||
append bool
|
||||
|
||||
// Writer callbacks
|
||||
|
||||
@@ -276,6 +283,15 @@ type openWriterParams struct {
|
||||
setObj func(*ObjectAttrs)
|
||||
}
|
||||
|
||||
type newMultiRangeDownloaderParams struct {
|
||||
bucket string
|
||||
conds *Conditions
|
||||
encryptionKey []byte
|
||||
gen int64
|
||||
object string
|
||||
handle *ReadHandle
|
||||
}
|
||||
|
||||
type newRangeReaderParams struct {
|
||||
bucket string
|
||||
conds *Conditions
|
||||
@@ -285,6 +301,7 @@ type newRangeReaderParams struct {
|
||||
object string
|
||||
offset int64
|
||||
readCompressed bool // Use accept-encoding: gzip. Only works for HTTP currently.
|
||||
handle *ReadHandle
|
||||
}
|
||||
|
||||
type getObjectParams struct {
|
||||
@@ -312,6 +329,13 @@ type restoreObjectParams struct {
|
||||
copySourceACL bool
|
||||
}
|
||||
|
||||
type moveObjectParams struct {
|
||||
bucket, srcObject, dstObject string
|
||||
srcConds *Conditions
|
||||
dstConds *Conditions
|
||||
encryptionKey []byte
|
||||
}
|
||||
|
||||
type composeObjectRequest struct {
|
||||
dstBucket string
|
||||
dstObject destinationObject
|
||||
|
||||
+1
-1
@@ -89,4 +89,4 @@ then
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
go test -v -timeout 10m ./ -run="^Test(RetryConformance|.*Emulated)$" -short 2>&1 | tee -a sponge_log.log
|
||||
go test -v -timeout 15m ./ ./dataflux -run="^Test(RetryConformance|.*Emulated)$" -short 2>&1 | tee -a sponge_log.log
|
||||
+29
-1
@@ -25,10 +25,26 @@ import (
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/storage/internal"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
// WithReadStallTimeout provides a [ClientOption] that may be passed to [storage.NewClient].
|
||||
// WithMetricInterval provides a [option.ClientOption] that may be passed to [storage.NewGRPCClient].
|
||||
// It sets how often to emit metrics [metric.WithInterval] when using
|
||||
// [metric.NewPeriodicReader]
|
||||
// When using Cloud Monitoring interval must be at minimum 1 [time.Minute].
|
||||
func WithMetricInterval(metricInterval time.Duration) option.ClientOption {
|
||||
return internal.WithMetricInterval.(func(time.Duration) option.ClientOption)(metricInterval)
|
||||
}
|
||||
|
||||
// WithMetricExporter provides a [option.ClientOption] that may be passed to [storage.NewGRPCClient].
|
||||
// Set an alternate client-side metric Exporter to emit metrics through.
|
||||
// Must implement [metric.Exporter]
|
||||
func WithMetricExporter(ex *metric.Exporter) option.ClientOption {
|
||||
return internal.WithMetricExporter.(func(*metric.Exporter) option.ClientOption)(ex)
|
||||
}
|
||||
|
||||
// WithReadStallTimeout provides a [option.ClientOption] that may be passed to [storage.NewClient].
|
||||
// It enables the client to retry stalled requests when starting a download from
|
||||
// Cloud Storage. If the timeout elapses with no response from the server, the request
|
||||
// is automatically retried.
|
||||
@@ -57,3 +73,15 @@ type ReadStallTimeoutConfig struct {
|
||||
// and retried.
|
||||
TargetPercentile float64
|
||||
}
|
||||
|
||||
// WithGRPCBidiReads provides an [option.ClientOption] that may be passed to
|
||||
// [cloud.google.com/go/storage.NewGRPCClient].
|
||||
// It enables the client to use bi-directional gRPC APIs for downloads rather than the
|
||||
// server streaming API. In particular, it allows users to use the [storage.MultiRangeDownloader]
|
||||
// surface, which requires bi-directional streaming.
|
||||
//
|
||||
// The bi-directional API is in private preview; please contact your account manager if
|
||||
// interested.
|
||||
func WithGRPCBidiReads() option.ClientOption {
|
||||
return internal.WithGRPCBidiReads.(func() option.ClientOption)()
|
||||
}
|
||||
+1018
-437
File diff suppressed because it is too large.
Load diff
+194
-186
@@ -16,8 +16,8 @@ package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -29,8 +29,8 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/transport"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/experimental/stats"
|
||||
"google.golang.org/grpc/stats/opentelemetry"
|
||||
)
|
||||
|
||||
@@ -39,6 +39,196 @@ const (
|
||||
metricPrefix = "storage.googleapis.com/client/"
|
||||
)
|
||||
|
||||
// Added to help with tests
|
||||
type storageMonitoredResource struct {
|
||||
project string
|
||||
api string
|
||||
location string
|
||||
instance string
|
||||
cloudPlatform string
|
||||
host string
|
||||
resource *resource.Resource
|
||||
}
|
||||
|
||||
func (smr *storageMonitoredResource) exporter() (metric.Exporter, error) {
|
||||
exporter, err := mexporter.New(
|
||||
mexporter.WithProjectID(smr.project),
|
||||
mexporter.WithMetricDescriptorTypeFormatter(metricFormatter),
|
||||
mexporter.WithCreateServiceTimeSeries(),
|
||||
mexporter.WithMonitoredResourceDescription(monitoredResourceName, []string{"project_id", "location", "cloud_platform", "host_id", "instance_id", "api"}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("storage: creating metrics exporter: %w", err)
|
||||
}
|
||||
return exporter, nil
|
||||
}
|
||||
|
||||
func newStorageMonitoredResource(ctx context.Context, project, api string, opts ...resource.Option) (*storageMonitoredResource, error) {
|
||||
detectedAttrs, err := resource.New(ctx, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
smr := &storageMonitoredResource{
|
||||
instance: uuid.New().String(),
|
||||
api: api,
|
||||
project: project,
|
||||
}
|
||||
s := detectedAttrs.Set()
|
||||
// Attempt to use resource detector project id if project id wasn't
|
||||
// identified using ADC as a last resort. Otherwise metrics cannot be started.
|
||||
if p, present := s.Value("cloud.account.id"); present && smr.project == "" {
|
||||
smr.project = p.AsString()
|
||||
} else if !present && smr.project == "" {
|
||||
return nil, errors.New("google cloud project is required to start client-side metrics")
|
||||
}
|
||||
if v, ok := s.Value("cloud.region"); ok {
|
||||
smr.location = v.AsString()
|
||||
} else {
|
||||
smr.location = "global"
|
||||
}
|
||||
if v, ok := s.Value("cloud.platform"); ok {
|
||||
smr.cloudPlatform = v.AsString()
|
||||
} else {
|
||||
smr.cloudPlatform = "unknown"
|
||||
}
|
||||
if v, ok := s.Value("host.id"); ok {
|
||||
smr.host = v.AsString()
|
||||
} else if v, ok := s.Value("faas.id"); ok {
|
||||
smr.host = v.AsString()
|
||||
} else {
|
||||
smr.host = "unknown"
|
||||
}
|
||||
smr.resource, err = resource.New(ctx, resource.WithAttributes([]attribute.KeyValue{
|
||||
{Key: "gcp.resource_type", Value: attribute.StringValue(monitoredResourceName)},
|
||||
{Key: "project_id", Value: attribute.StringValue(smr.project)},
|
||||
{Key: "api", Value: attribute.StringValue(smr.api)},
|
||||
{Key: "instance_id", Value: attribute.StringValue(smr.instance)},
|
||||
{Key: "location", Value: attribute.StringValue(smr.location)},
|
||||
{Key: "cloud_platform", Value: attribute.StringValue(smr.cloudPlatform)},
|
||||
{Key: "host_id", Value: attribute.StringValue(smr.host)},
|
||||
}...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return smr, nil
|
||||
}
|
||||
|
||||
type metricsContext struct {
|
||||
// client options passed to gRPC channels
|
||||
clientOpts []option.ClientOption
|
||||
// instance of metric reader used by gRPC client-side metrics
|
||||
provider *metric.MeterProvider
|
||||
// clean func to call when closing gRPC client
|
||||
close func()
|
||||
}
|
||||
|
||||
type metricsConfig struct {
|
||||
project string
|
||||
interval time.Duration
|
||||
customExporter *metric.Exporter
|
||||
manualReader *metric.ManualReader // used by tests
|
||||
disableExporter bool // used by tests disables exports
|
||||
resourceOpts []resource.Option // used by tests
|
||||
}
|
||||
|
||||
func newGRPCMetricContext(ctx context.Context, cfg metricsConfig) (*metricsContext, error) {
|
||||
var exporter metric.Exporter
|
||||
meterOpts := []metric.Option{}
|
||||
if cfg.customExporter == nil {
|
||||
var ropts []resource.Option
|
||||
if cfg.resourceOpts != nil {
|
||||
ropts = cfg.resourceOpts
|
||||
} else {
|
||||
ropts = []resource.Option{resource.WithDetectors(gcp.NewDetector())}
|
||||
}
|
||||
smr, err := newStorageMonitoredResource(ctx, cfg.project, "grpc", ropts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exporter, err = smr.exporter()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meterOpts = append(meterOpts, metric.WithResource(smr.resource))
|
||||
} else {
|
||||
exporter = *cfg.customExporter
|
||||
}
|
||||
interval := time.Minute
|
||||
if cfg.interval > 0 {
|
||||
interval = cfg.interval
|
||||
}
|
||||
meterOpts = append(meterOpts,
|
||||
// Metric views update histogram boundaries to be relevant to GCS
|
||||
// otherwise default OTel histogram boundaries are used.
|
||||
metric.WithView(
|
||||
createHistogramView("grpc.client.attempt.duration", latencyHistogramBoundaries()),
|
||||
createHistogramView("grpc.client.attempt.rcvd_total_compressed_message_size", sizeHistogramBoundaries()),
|
||||
createHistogramView("grpc.client.attempt.sent_total_compressed_message_size", sizeHistogramBoundaries())),
|
||||
)
|
||||
if cfg.manualReader != nil {
|
||||
meterOpts = append(meterOpts, metric.WithReader(cfg.manualReader))
|
||||
}
|
||||
if !cfg.disableExporter {
|
||||
meterOpts = append(meterOpts, metric.WithReader(
|
||||
metric.NewPeriodicReader(&exporterLogSuppressor{Exporter: exporter}, metric.WithInterval(interval))))
|
||||
}
|
||||
provider := metric.NewMeterProvider(meterOpts...)
|
||||
mo := opentelemetry.MetricsOptions{
|
||||
MeterProvider: provider,
|
||||
Metrics: stats.NewMetrics(
|
||||
"grpc.client.attempt.started",
|
||||
"grpc.client.attempt.duration",
|
||||
"grpc.client.attempt.sent_total_compressed_message_size",
|
||||
"grpc.client.attempt.rcvd_total_compressed_message_size",
|
||||
"grpc.client.call.duration",
|
||||
"grpc.lb.wrr.rr_fallback",
|
||||
"grpc.lb.wrr.endpoint_weight_not_yet_usable",
|
||||
"grpc.lb.wrr.endpoint_weight_stale",
|
||||
"grpc.lb.wrr.endpoint_weights",
|
||||
"grpc.lb.rls.cache_entries",
|
||||
"grpc.lb.rls.cache_size",
|
||||
"grpc.lb.rls.default_target_picks",
|
||||
"grpc.lb.rls.target_picks",
|
||||
"grpc.lb.rls.failed_picks",
|
||||
),
|
||||
OptionalLabels: []string{"grpc.lb.locality"},
|
||||
}
|
||||
opts := []option.ClientOption{
|
||||
option.WithGRPCDialOption(
|
||||
opentelemetry.DialOption(opentelemetry.Options{MetricsOptions: mo})),
|
||||
option.WithGRPCDialOption(
|
||||
grpc.WithDefaultCallOptions(grpc.StaticMethodCallOption{})),
|
||||
}
|
||||
return &metricsContext{
|
||||
clientOpts: opts,
|
||||
provider: provider,
|
||||
close: func() {
|
||||
provider.Shutdown(ctx)
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Silences permission errors after initial error is emitted to prevent
|
||||
// chatty logs.
|
||||
type exporterLogSuppressor struct {
|
||||
metric.Exporter
|
||||
emittedFailure bool
|
||||
}
|
||||
|
||||
// Implements OTel SDK metric.Exporter interface to prevent noisy logs from
|
||||
// lack of credentials after initial failure.
|
||||
// https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric@v1.28.0#Exporter
|
||||
func (e *exporterLogSuppressor) Export(ctx context.Context, rm *metricdata.ResourceMetrics) error {
|
||||
if err := e.Exporter.Export(ctx, rm); err != nil && !e.emittedFailure {
|
||||
if strings.Contains(err.Error(), "PermissionDenied") {
|
||||
e.emittedFailure = true
|
||||
return fmt.Errorf("gRPC metrics failed due permission issue: %w", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func latencyHistogramBoundaries() []float64 {
|
||||
boundaries := []float64{}
|
||||
boundary := 0.0
|
||||
@@ -78,72 +268,6 @@ func sizeHistogramBoundaries() []float64 {
|
||||
return boundaries
|
||||
}
|
||||
|
||||
func metricFormatter(m metricdata.Metrics) string {
|
||||
return metricPrefix + strings.ReplaceAll(string(m.Name), ".", "/")
|
||||
}
|
||||
|
||||
func gcpAttributeExpectedDefaults() []attribute.KeyValue {
|
||||
return []attribute.KeyValue{
|
||||
{Key: "location", Value: attribute.StringValue("global")},
|
||||
{Key: "cloud_platform", Value: attribute.StringValue("unknown")},
|
||||
{Key: "host_id", Value: attribute.StringValue("unknown")}}
|
||||
}
|
||||
|
||||
// Added to help with tests
|
||||
type preparedResource struct {
|
||||
projectToUse string
|
||||
resource *resource.Resource
|
||||
}
|
||||
|
||||
func newPreparedResource(ctx context.Context, project string, resourceOptions []resource.Option) (*preparedResource, error) {
|
||||
detectedAttrs, err := resource.New(ctx, resourceOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preparedResource := &preparedResource{}
|
||||
s := detectedAttrs.Set()
|
||||
p, present := s.Value("cloud.account.id")
|
||||
if present {
|
||||
preparedResource.projectToUse = p.AsString()
|
||||
} else {
|
||||
preparedResource.projectToUse = project
|
||||
}
|
||||
updates := []attribute.KeyValue{}
|
||||
for _, kv := range gcpAttributeExpectedDefaults() {
|
||||
if val, present := s.Value(kv.Key); !present || val.AsString() == "" {
|
||||
updates = append(updates, attribute.KeyValue{Key: kv.Key, Value: kv.Value})
|
||||
}
|
||||
}
|
||||
r, err := resource.New(
|
||||
ctx,
|
||||
resource.WithAttributes(
|
||||
attribute.KeyValue{Key: "gcp.resource_type", Value: attribute.StringValue(monitoredResourceName)},
|
||||
attribute.KeyValue{Key: "instance_id", Value: attribute.StringValue(uuid.New().String())},
|
||||
attribute.KeyValue{Key: "project_id", Value: attribute.StringValue(project)},
|
||||
attribute.KeyValue{Key: "api", Value: attribute.StringValue("grpc")},
|
||||
),
|
||||
resource.WithAttributes(detectedAttrs.Attributes()...),
|
||||
// Last duplicate key / value wins
|
||||
resource.WithAttributes(updates...),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preparedResource.resource = r
|
||||
return preparedResource, nil
|
||||
}
|
||||
|
||||
type metricsContext struct {
|
||||
// project used by exporter
|
||||
project string
|
||||
// client options passed to gRPC channels
|
||||
clientOpts []option.ClientOption
|
||||
// instance of metric reader used by gRPC client-side metrics
|
||||
provider *metric.MeterProvider
|
||||
// clean func to call when closing gRPC client
|
||||
close func()
|
||||
}
|
||||
|
||||
func createHistogramView(name string, boundaries []float64) metric.View {
|
||||
return metric.NewView(metric.Instrument{
|
||||
Name: name,
|
||||
@@ -154,122 +278,6 @@ func createHistogramView(name string, boundaries []float64) metric.View {
|
||||
})
|
||||
}
|
||||
|
||||
func newGRPCMetricContext(ctx context.Context, project string) (*metricsContext, error) {
|
||||
preparedResource, err := newPreparedResource(ctx, project, []resource.Option{resource.WithDetectors(gcp.NewDetector())})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Implementation requires a project, if one is not determined possibly user
|
||||
// credentials. Then we will fail stating gRPC Metrics require a project-id.
|
||||
if project == "" && preparedResource.projectToUse != "" {
|
||||
return nil, fmt.Errorf("google cloud project is required to start client-side metrics")
|
||||
}
|
||||
// If projectTouse isn't the same as project provided to Storage client, then
|
||||
// emit a log stating which project is being used to emit metrics to.
|
||||
if project != preparedResource.projectToUse {
|
||||
log.Printf("The Project ID configured for metrics is %s, but the Project ID of the storage client is %s. Make sure that the service account in use has the required metric writing role (roles/monitoring.metricWriter) in the project projectIdToUse or metrics will not be written.", preparedResource.projectToUse, project)
|
||||
}
|
||||
meOpts := []mexporter.Option{
|
||||
mexporter.WithProjectID(preparedResource.projectToUse),
|
||||
mexporter.WithMetricDescriptorTypeFormatter(metricFormatter),
|
||||
mexporter.WithCreateServiceTimeSeries(),
|
||||
mexporter.WithMonitoredResourceDescription(monitoredResourceName, []string{"project_id", "location", "cloud_platform", "host_id", "instance_id", "api"})}
|
||||
exporter, err := mexporter.New(meOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Metric views update histogram boundaries to be relevant to GCS
|
||||
// otherwise default OTel histogram boundaries are used.
|
||||
metricViews := []metric.View{
|
||||
createHistogramView("grpc.client.attempt.duration", latencyHistogramBoundaries()),
|
||||
createHistogramView("grpc.client.attempt.rcvd_total_compressed_message_size", sizeHistogramBoundaries()),
|
||||
createHistogramView("grpc.client.attempt.sent_total_compressed_message_size", sizeHistogramBoundaries()),
|
||||
}
|
||||
provider := metric.NewMeterProvider(
|
||||
metric.WithReader(metric.NewPeriodicReader(&exporterLogSuppressor{exporter: exporter}, metric.WithInterval(time.Minute))),
|
||||
metric.WithResource(preparedResource.resource),
|
||||
metric.WithView(metricViews...),
|
||||
)
|
||||
mo := opentelemetry.MetricsOptions{
|
||||
MeterProvider: provider,
|
||||
Metrics: opentelemetry.DefaultMetrics().Add(
|
||||
"grpc.lb.wrr.rr_fallback",
|
||||
"grpc.lb.wrr.endpoint_weight_not_yet_usable",
|
||||
"grpc.lb.wrr.endpoint_weight_stale",
|
||||
"grpc.lb.wrr.endpoint_weights",
|
||||
"grpc.lb.rls.cache_entries",
|
||||
"grpc.lb.rls.cache_size",
|
||||
"grpc.lb.rls.default_target_picks",
|
||||
"grpc.lb.rls.target_picks",
|
||||
"grpc.lb.rls.failed_picks"),
|
||||
OptionalLabels: []string{"grpc.lb.locality"},
|
||||
}
|
||||
opts := []option.ClientOption{
|
||||
option.WithGRPCDialOption(opentelemetry.DialOption(opentelemetry.Options{MetricsOptions: mo})),
|
||||
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(grpc.StaticMethodCallOption{})),
|
||||
}
|
||||
context := &metricsContext{
|
||||
project: preparedResource.projectToUse,
|
||||
clientOpts: opts,
|
||||
provider: provider,
|
||||
close: createShutdown(ctx, provider),
|
||||
}
|
||||
return context, nil
|
||||
}
|
||||
|
||||
func enableClientMetrics(ctx context.Context, s *settings) (*metricsContext, error) {
|
||||
var project string
|
||||
c, err := transport.Creds(ctx, s.clientOption...)
|
||||
if err == nil {
|
||||
project = c.ProjectID
|
||||
}
|
||||
// Enable client-side metrics for gRPC
|
||||
metricsContext, err := newGRPCMetricContext(ctx, project)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gRPC Metrics: %w", err)
|
||||
}
|
||||
return metricsContext, nil
|
||||
}
|
||||
|
||||
func createShutdown(ctx context.Context, provider *metric.MeterProvider) func() {
|
||||
return func() {
|
||||
provider.Shutdown(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// Silences permission errors after initial error is emitted to prevent
|
||||
// chatty logs.
|
||||
type exporterLogSuppressor struct {
|
||||
exporter metric.Exporter
|
||||
emittedFailure bool
|
||||
}
|
||||
|
||||
// Implements OTel SDK metric.Exporter interface to prevent noisy logs from
|
||||
// lack of credentials after initial failure.
|
||||
// https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric@v1.28.0#Exporter
|
||||
func (e *exporterLogSuppressor) Export(ctx context.Context, rm *metricdata.ResourceMetrics) error {
|
||||
if err := e.exporter.Export(ctx, rm); err != nil && !e.emittedFailure {
|
||||
if strings.Contains(err.Error(), "PermissionDenied") {
|
||||
e.emittedFailure = true
|
||||
return fmt.Errorf("gRPC metrics failed due permission issue: %w", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *exporterLogSuppressor) Temporality(k metric.InstrumentKind) metricdata.Temporality {
|
||||
return e.exporter.Temporality(k)
|
||||
}
|
||||
|
||||
func (e *exporterLogSuppressor) Aggregation(k metric.InstrumentKind) metric.Aggregation {
|
||||
return e.exporter.Aggregation(k)
|
||||
}
|
||||
|
||||
func (e *exporterLogSuppressor) ForceFlush(ctx context.Context) error {
|
||||
return e.exporter.ForceFlush(ctx)
|
||||
}
|
||||
|
||||
func (e *exporterLogSuppressor) Shutdown(ctx context.Context) error {
|
||||
return e.exporter.Shutdown(ctx)
|
||||
func metricFormatter(m metricdata.Metrics) string {
|
||||
return metricPrefix + strings.ReplaceAll(string(m.Name), ".", "/")
|
||||
}
|
||||
+870
@@ -0,0 +1,870 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
"cloud.google.com/go/storage/internal/apiv2/storagepb"
|
||||
"github.com/googleapis/gax-go/v2"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/grpc/mem"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/encoding/protowire"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Below is the legacy implementation of gRPC downloads using the ReadObject API.
|
||||
// It's used by gRPC if the experimental option WithGRPCBidiReads was not passed.
|
||||
// TODO: once BidiReadObject is in GA, remove this implementation.
|
||||
|
||||
// Custom codec to be used for unmarshaling ReadObjectResponse messages.
|
||||
// This is used to avoid a copy of object data in proto.Unmarshal.
|
||||
type bytesCodecReadObject struct {
|
||||
}
|
||||
|
||||
var _ encoding.CodecV2 = bytesCodecReadObject{}
|
||||
|
||||
// Marshal is used to encode messages to send for bytesCodecReadObject. Since we are only
|
||||
// using this to send ReadObjectRequest messages we don't need to recycle buffers
|
||||
// here.
|
||||
func (bytesCodecReadObject) Marshal(v any) (mem.BufferSlice, error) {
|
||||
vv, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v)
|
||||
}
|
||||
var data mem.BufferSlice
|
||||
buf, err := proto.Marshal(vv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = append(data, mem.SliceBuffer(buf))
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// Unmarshal is used for data received for ReadObjectResponse. We want to preserve
|
||||
// the mem.BufferSlice in most cases rather than copying and calling proto.Unmarshal.
|
||||
func (bytesCodecReadObject) Unmarshal(data mem.BufferSlice, v any) error {
|
||||
switch v := v.(type) {
|
||||
case *mem.BufferSlice:
|
||||
*v = data
|
||||
// Pick up a reference to the data so that it is not freed while decoding.
|
||||
data.Ref()
|
||||
return nil
|
||||
case proto.Message:
|
||||
buf := data.MaterializeToBuffer(mem.DefaultBufferPool())
|
||||
return proto.Unmarshal(buf.ReadOnlyData(), v)
|
||||
default:
|
||||
return fmt.Errorf("cannot unmarshal type %T, want proto.Message or mem.BufferSlice", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (bytesCodecReadObject) Name() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *grpcStorageClient) NewRangeReaderReadObject(ctx context.Context, params *newRangeReaderParams, opts ...storageOption) (r *Reader, err error) {
|
||||
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.grpcStorageClient.NewRangeReaderReadObject")
|
||||
defer func() { trace.EndSpan(ctx, err) }()
|
||||
|
||||
s := callSettings(c.settings, opts...)
|
||||
|
||||
s.gax = append(s.gax, gax.WithGRPCOptions(
|
||||
grpc.ForceCodecV2(bytesCodecReadObject{}),
|
||||
))
|
||||
|
||||
if s.userProject != "" {
|
||||
ctx = setUserProjectMetadata(ctx, s.userProject)
|
||||
}
|
||||
|
||||
b := bucketResourceName(globalProjectAlias, params.bucket)
|
||||
req := &storagepb.ReadObjectRequest{
|
||||
Bucket: b,
|
||||
Object: params.object,
|
||||
CommonObjectRequestParams: toProtoCommonObjectRequestParams(params.encryptionKey),
|
||||
}
|
||||
// The default is a negative value, which means latest.
|
||||
if params.gen >= 0 {
|
||||
req.Generation = params.gen
|
||||
}
|
||||
|
||||
// Define a function that initiates a Read with offset and length, assuming
|
||||
// we have already read seen bytes.
|
||||
reopen := func(seen int64) (*readStreamResponseReadObject, context.CancelFunc, error) {
|
||||
// If the context has already expired, return immediately without making
|
||||
// we call.
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cc, cancel := context.WithCancel(ctx)
|
||||
|
||||
req.ReadOffset = params.offset + seen
|
||||
|
||||
// Only set a ReadLimit if length is greater than zero, because <= 0 means
|
||||
// to read it all.
|
||||
if params.length > 0 {
|
||||
req.ReadLimit = params.length - seen
|
||||
}
|
||||
|
||||
if err := applyCondsProto("gRPCReadObjectReader.reopen", params.gen, params.conds, req); err != nil {
|
||||
cancel()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var stream storagepb.Storage_ReadObjectClient
|
||||
var err error
|
||||
var decoder *readObjectResponseDecoder
|
||||
|
||||
err = run(cc, func(ctx context.Context) error {
|
||||
stream, err = c.raw.ReadObject(ctx, req, s.gax...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Receive the message into databuf as a wire-encoded message so we can
|
||||
// use a custom decoder to avoid an extra copy at the protobuf layer.
|
||||
databufs := mem.BufferSlice{}
|
||||
err := stream.RecvMsg(&databufs)
|
||||
// These types of errors show up on the Recv call, rather than the
|
||||
// initialization of the stream via ReadObject above.
|
||||
if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
|
||||
return ErrObjectNotExist
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Use a custom decoder that uses protobuf unmarshalling for all
|
||||
// fields except the object data. Object data is handled separately
|
||||
// to avoid a copy.
|
||||
decoder = &readObjectResponseDecoder{
|
||||
databufs: databufs,
|
||||
}
|
||||
err = decoder.readFullObjectResponse()
|
||||
return err
|
||||
}, s.retry, s.idempotent)
|
||||
if err != nil {
|
||||
// Close the stream context we just created to ensure we don't leak
|
||||
// resources.
|
||||
cancel()
|
||||
// Free any buffers.
|
||||
if decoder != nil && decoder.databufs != nil {
|
||||
decoder.databufs.Free()
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &readStreamResponseReadObject{stream, decoder}, cancel, nil
|
||||
}
|
||||
|
||||
res, cancel, err := reopen(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The first message was Recv'd on stream open, use it to populate the
|
||||
// object metadata.
|
||||
msg := res.decoder.msg
|
||||
obj := msg.GetMetadata()
|
||||
// This is the size of the entire object, even if only a range was requested.
|
||||
size := obj.GetSize()
|
||||
|
||||
// Only support checksums when reading an entire object, not a range.
|
||||
var (
|
||||
wantCRC uint32
|
||||
checkCRC bool
|
||||
)
|
||||
if checksums := msg.GetObjectChecksums(); checksums != nil && checksums.Crc32C != nil {
|
||||
if params.offset == 0 && params.length < 0 {
|
||||
checkCRC = true
|
||||
}
|
||||
wantCRC = checksums.GetCrc32C()
|
||||
}
|
||||
|
||||
metadata := obj.GetMetadata()
|
||||
r = &Reader{
|
||||
Attrs: ReaderObjectAttrs{
|
||||
Size: size,
|
||||
ContentType: obj.GetContentType(),
|
||||
ContentEncoding: obj.GetContentEncoding(),
|
||||
CacheControl: obj.GetCacheControl(),
|
||||
LastModified: obj.GetUpdateTime().AsTime(),
|
||||
Metageneration: obj.GetMetageneration(),
|
||||
Generation: obj.GetGeneration(),
|
||||
CRC32C: wantCRC,
|
||||
},
|
||||
objectMetadata: &metadata,
|
||||
reader: &gRPCReadObjectReader{
|
||||
stream: res.stream,
|
||||
reopen: reopen,
|
||||
cancel: cancel,
|
||||
size: size,
|
||||
// Preserve the decoder to read out object data when Read/WriteTo is called.
|
||||
currMsg: res.decoder,
|
||||
settings: s,
|
||||
zeroRange: params.length == 0,
|
||||
wantCRC: wantCRC,
|
||||
checkCRC: checkCRC,
|
||||
},
|
||||
checkCRC: checkCRC,
|
||||
}
|
||||
|
||||
cr := msg.GetContentRange()
|
||||
if cr != nil {
|
||||
r.Attrs.StartOffset = cr.GetStart()
|
||||
r.remain = cr.GetEnd() - cr.GetStart()
|
||||
} else {
|
||||
r.remain = size
|
||||
}
|
||||
|
||||
// For a zero-length request, explicitly close the stream and set remaining
|
||||
// bytes to zero.
|
||||
if params.length == 0 {
|
||||
r.remain = 0
|
||||
r.reader.Close()
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type readStreamResponseReadObject struct {
|
||||
stream storagepb.Storage_ReadObjectClient
|
||||
decoder *readObjectResponseDecoder
|
||||
}
|
||||
|
||||
type gRPCReadObjectReader struct {
|
||||
seen, size int64
|
||||
zeroRange bool
|
||||
stream storagepb.Storage_ReadObjectClient
|
||||
reopen func(seen int64) (*readStreamResponseReadObject, context.CancelFunc, error)
|
||||
leftovers []byte
|
||||
currMsg *readObjectResponseDecoder // decoder for the current message
|
||||
cancel context.CancelFunc
|
||||
settings *settings
|
||||
checkCRC bool // should we check the CRC?
|
||||
wantCRC uint32 // the CRC32c value the server sent in the header
|
||||
gotCRC uint32 // running crc
|
||||
}
|
||||
|
||||
// Update the running CRC with the data in the slice, if CRC checking was enabled.
|
||||
func (r *gRPCReadObjectReader) updateCRC(b []byte) {
|
||||
if r.checkCRC {
|
||||
r.gotCRC = crc32.Update(r.gotCRC, crc32cTable, b)
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether the CRC matches at the conclusion of a read, if CRC checking was enabled.
|
||||
func (r *gRPCReadObjectReader) runCRCCheck() error {
|
||||
if r.checkCRC && r.gotCRC != r.wantCRC {
|
||||
return fmt.Errorf("storage: bad CRC on read: got %d, want %d", r.gotCRC, r.wantCRC)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read reads bytes into the user's buffer from an open gRPC stream.
|
||||
func (r *gRPCReadObjectReader) Read(p []byte) (int, error) {
|
||||
// The entire object has been read by this reader, check the checksum if
|
||||
// necessary and return EOF.
|
||||
if r.size == r.seen || r.zeroRange {
|
||||
if err := r.runCRCCheck(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
// No stream to read from, either never initialized or Close was called.
|
||||
// Note: There is a potential concurrency issue if multiple routines are
|
||||
// using the same reader. One encounters an error and the stream is closed
|
||||
// and then reopened while the other routine attempts to read from it.
|
||||
if r.stream == nil {
|
||||
return 0, fmt.Errorf("storage: reader has been closed")
|
||||
}
|
||||
|
||||
var n int
|
||||
|
||||
// If there is data remaining in the current message, return what was
|
||||
// available to conform to the Reader
|
||||
// interface: https://pkg.go.dev/io#Reader.
|
||||
if !r.currMsg.done {
|
||||
n = r.currMsg.readAndUpdateCRC(p, func(b []byte) {
|
||||
r.updateCRC(b)
|
||||
})
|
||||
r.seen += int64(n)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Attempt to Recv the next message on the stream.
|
||||
// This will update r.currMsg with the decoder for the new message.
|
||||
err := r.recv()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// TODO: Determine if we need to capture incremental CRC32C for this
|
||||
// chunk. The Object CRC32C checksum is captured when directed to read
|
||||
// the entire Object. If directed to read a range, we may need to
|
||||
// calculate the range's checksum for verification if the checksum is
|
||||
// present in the response here.
|
||||
// TODO: Figure out if we need to support decompressive transcoding
|
||||
// https://cloud.google.com/storage/docs/transcoding.
|
||||
|
||||
n = r.currMsg.readAndUpdateCRC(p, func(b []byte) {
|
||||
r.updateCRC(b)
|
||||
})
|
||||
r.seen += int64(n)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// WriteTo writes all the data requested by the Reader into w, implementing
|
||||
// io.WriterTo.
|
||||
func (r *gRPCReadObjectReader) WriteTo(w io.Writer) (int64, error) {
|
||||
// The entire object has been read by this reader, check the checksum if
|
||||
// necessary and return nil.
|
||||
if r.size == r.seen || r.zeroRange {
|
||||
if err := r.runCRCCheck(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// No stream to read from, either never initialized or Close was called.
|
||||
// Note: There is a potential concurrency issue if multiple routines are
|
||||
// using the same reader. One encounters an error and the stream is closed
|
||||
// and then reopened while the other routine attempts to read from it.
|
||||
if r.stream == nil {
|
||||
return 0, fmt.Errorf("storage: reader has been closed")
|
||||
}
|
||||
|
||||
// Track bytes written during before call.
|
||||
var alreadySeen = r.seen
|
||||
|
||||
// Write any already received message to the stream. There will be some leftovers from the
|
||||
// original NewRangeReaderReadObject call.
|
||||
if r.currMsg != nil && !r.currMsg.done {
|
||||
written, err := r.currMsg.writeToAndUpdateCRC(w, func(b []byte) {
|
||||
r.updateCRC(b)
|
||||
})
|
||||
r.seen += int64(written)
|
||||
r.currMsg = nil
|
||||
if err != nil {
|
||||
return r.seen - alreadySeen, err
|
||||
}
|
||||
}
|
||||
|
||||
// Loop and receive additional messages until the entire data is written.
|
||||
for {
|
||||
// Attempt to receive the next message on the stream.
|
||||
// Will terminate with io.EOF once data has all come through.
|
||||
// recv() handles stream reopening and retry logic so no need for retries here.
|
||||
err := r.recv()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// We are done; check the checksum if necessary and return.
|
||||
err = r.runCRCCheck()
|
||||
}
|
||||
return r.seen - alreadySeen, err
|
||||
}
|
||||
|
||||
// TODO: Determine if we need to capture incremental CRC32C for this
|
||||
// chunk. The Object CRC32C checksum is captured when directed to read
|
||||
// the entire Object. If directed to read a range, we may need to
|
||||
// calculate the range's checksum for verification if the checksum is
|
||||
// present in the response here.
|
||||
// TODO: Figure out if we need to support decompressive transcoding
|
||||
// https://cloud.google.com/storage/docs/transcoding.
|
||||
written, err := r.currMsg.writeToAndUpdateCRC(w, func(b []byte) {
|
||||
r.updateCRC(b)
|
||||
})
|
||||
r.seen += int64(written)
|
||||
if err != nil {
|
||||
return r.seen - alreadySeen, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Close cancels the read stream's context in order for it to be closed and
|
||||
// collected, and frees any currently in use buffers.
|
||||
func (r *gRPCReadObjectReader) Close() error {
|
||||
if r.cancel != nil {
|
||||
r.cancel()
|
||||
}
|
||||
r.stream = nil
|
||||
r.currMsg = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// recv attempts to Recv the next message on the stream and extract the object
|
||||
// data that it contains. In the event that a retryable error is encountered,
|
||||
// the stream will be closed, reopened, and RecvMsg again.
|
||||
// This will attempt to Recv until one of the following is true:
|
||||
//
|
||||
// * Recv is successful
|
||||
// * A non-retryable error is encountered
|
||||
// * The Reader's context is canceled
|
||||
//
|
||||
// The last error received is the one that is returned, which could be from
|
||||
// an attempt to reopen the stream.
|
||||
func (r *gRPCReadObjectReader) recv() error {
|
||||
databufs := mem.BufferSlice{}
|
||||
err := r.stream.RecvMsg(&databufs)
|
||||
|
||||
var shouldRetry = ShouldRetry
|
||||
if r.settings.retry != nil && r.settings.retry.shouldRetry != nil {
|
||||
shouldRetry = r.settings.retry.shouldRetry
|
||||
}
|
||||
if err != nil && shouldRetry(err) {
|
||||
// This will "close" the existing stream and immediately attempt to
|
||||
// reopen the stream, but will backoff if further attempts are necessary.
|
||||
// Reopening the stream Recvs the first message, so if retrying is
|
||||
// successful, r.currMsg will be updated to include the new data.
|
||||
return r.reopenStream()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.currMsg = &readObjectResponseDecoder{databufs: databufs}
|
||||
return r.currMsg.readFullObjectResponse()
|
||||
}
|
||||
|
||||
// ReadObjectResponse field and subfield numbers.
|
||||
const (
|
||||
checksummedDataFieldReadObject = protowire.Number(1)
|
||||
checksummedDataContentFieldReadObject = protowire.Number(1)
|
||||
checksummedDataCRC32CFieldReadObject = protowire.Number(2)
|
||||
objectChecksumsFieldReadObject = protowire.Number(2)
|
||||
contentRangeFieldReadObject = protowire.Number(3)
|
||||
metadataFieldReadObject = protowire.Number(4)
|
||||
)
|
||||
|
||||
// readObjectResponseDecoder is a wrapper on the raw message, used to decode one message
|
||||
// without copying object data. It also has methods to write out the resulting object
|
||||
// data to the user application.
|
||||
type readObjectResponseDecoder struct {
|
||||
databufs mem.BufferSlice // raw bytes of the message being processed
|
||||
// Decoding offsets
|
||||
off uint64 // offset in the messsage relative to the data as a whole
|
||||
currBuf int // index of the current buffer being processed
|
||||
currOff uint64 // offset in the current buffer
|
||||
// Processed data
|
||||
msg *storagepb.ReadObjectResponse // processed response message with all fields other than object data populated
|
||||
dataOffsets bufferSliceOffsetsReadObject // offsets of the object data in the message.
|
||||
done bool // true if the data has been completely read.
|
||||
}
|
||||
|
||||
type bufferSliceOffsetsReadObject struct {
|
||||
startBuf, endBuf int // indices of start and end buffers of object data in the msg
|
||||
startOff, endOff uint64 // offsets within these buffers where the data starts and ends.
|
||||
currBuf int // index of current buffer being read out to the user application.
|
||||
currOff uint64 // offset of read in current buffer.
|
||||
}
|
||||
|
||||
// peek ahead 10 bytes from the current offset in the databufs. This will return a
|
||||
// slice of the current buffer if the bytes are all in one buffer, but will copy
|
||||
// the bytes into a new buffer if the distance is split across buffers. Use this
|
||||
// to allow protowire methods to be used to parse tags & fixed values.
|
||||
// The max length of a varint tag is 10 bytes, see
|
||||
// https://protobuf.dev/programming-guides/encoding/#varints . Other int types
|
||||
// are shorter.
|
||||
func (d *readObjectResponseDecoder) peek() []byte {
|
||||
b := d.databufs[d.currBuf].ReadOnlyData()
|
||||
// Check if the tag will fit in the current buffer. If not, copy the next 10
|
||||
// bytes into a new buffer to ensure that we can read the tag correctly
|
||||
// without it being divided between buffers.
|
||||
tagBuf := b[d.currOff:]
|
||||
remainingInBuf := len(tagBuf)
|
||||
// If we have less than 10 bytes remaining and are not in the final buffer,
|
||||
// copy up to 10 bytes ahead from the next buffer.
|
||||
if remainingInBuf < binary.MaxVarintLen64 && d.currBuf != len(d.databufs)-1 {
|
||||
tagBuf = d.copyNextBytes(10)
|
||||
}
|
||||
return tagBuf
|
||||
}
|
||||
|
||||
// Copies up to next n bytes into a new buffer, or fewer if fewer bytes remain in the
|
||||
// buffers overall. Does not advance offsets.
|
||||
func (d *readObjectResponseDecoder) copyNextBytes(n int) []byte {
|
||||
remaining := n
|
||||
if r := d.databufs.Len() - int(d.off); r < remaining {
|
||||
remaining = r
|
||||
}
|
||||
currBuf := d.currBuf
|
||||
currOff := d.currOff
|
||||
var buf []byte
|
||||
for remaining > 0 {
|
||||
b := d.databufs[currBuf].ReadOnlyData()
|
||||
remainingInCurr := len(b[currOff:])
|
||||
if remainingInCurr < remaining {
|
||||
buf = append(buf, b[currOff:]...)
|
||||
remaining -= remainingInCurr
|
||||
currBuf++
|
||||
currOff = 0
|
||||
} else {
|
||||
buf = append(buf, b[currOff:currOff+uint64(remaining)]...)
|
||||
remaining = 0
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// Advance current buffer & byte offset in the decoding by n bytes. Returns an error if we
|
||||
// go past the end of the data.
|
||||
func (d *readObjectResponseDecoder) advanceOffset(n uint64) error {
|
||||
remaining := n
|
||||
for remaining > 0 {
|
||||
remainingInCurr := uint64(d.databufs[d.currBuf].Len()) - d.currOff
|
||||
if remainingInCurr <= remaining {
|
||||
remaining -= remainingInCurr
|
||||
d.currBuf++
|
||||
d.currOff = 0
|
||||
} else {
|
||||
d.currOff += remaining
|
||||
remaining = 0
|
||||
}
|
||||
}
|
||||
// If we have advanced past the end of the buffers, something went wrong.
|
||||
if (d.currBuf == len(d.databufs) && d.currOff > 0) || d.currBuf > len(d.databufs) {
|
||||
return errors.New("decoding: truncated message, cannot advance offset")
|
||||
}
|
||||
d.off += n
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// This copies object data from the message into the buffer and returns the number of
|
||||
// bytes copied. The data offsets are incremented in the message. The updateCRC
|
||||
// function is called on the copied bytes.
|
||||
func (d *readObjectResponseDecoder) readAndUpdateCRC(p []byte, updateCRC func([]byte)) int {
|
||||
// For a completely empty message, just return 0
|
||||
if len(d.databufs) == 0 {
|
||||
return 0
|
||||
}
|
||||
databuf := d.databufs[d.dataOffsets.currBuf]
|
||||
startOff := d.dataOffsets.currOff
|
||||
var b []byte
|
||||
if d.dataOffsets.currBuf == d.dataOffsets.endBuf {
|
||||
b = databuf.ReadOnlyData()[startOff:d.dataOffsets.endOff]
|
||||
} else {
|
||||
b = databuf.ReadOnlyData()[startOff:]
|
||||
}
|
||||
n := copy(p, b)
|
||||
updateCRC(b[:n])
|
||||
d.dataOffsets.currOff += uint64(n)
|
||||
|
||||
// We've read all the data from this message. Free the underlying buffers.
|
||||
if d.dataOffsets.currBuf == d.dataOffsets.endBuf && d.dataOffsets.currOff == d.dataOffsets.endOff {
|
||||
d.done = true
|
||||
d.databufs.Free()
|
||||
}
|
||||
// We are at the end of the current buffer
|
||||
if d.dataOffsets.currBuf != d.dataOffsets.endBuf && d.dataOffsets.currOff == uint64(databuf.Len()) {
|
||||
d.dataOffsets.currOff = 0
|
||||
d.dataOffsets.currBuf++
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (d *readObjectResponseDecoder) writeToAndUpdateCRC(w io.Writer, updateCRC func([]byte)) (int64, error) {
|
||||
// For a completely empty message, just return 0
|
||||
if len(d.databufs) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
var written int64
|
||||
for !d.done {
|
||||
databuf := d.databufs[d.dataOffsets.currBuf]
|
||||
startOff := d.dataOffsets.currOff
|
||||
var b []byte
|
||||
if d.dataOffsets.currBuf == d.dataOffsets.endBuf {
|
||||
b = databuf.ReadOnlyData()[startOff:d.dataOffsets.endOff]
|
||||
} else {
|
||||
b = databuf.ReadOnlyData()[startOff:]
|
||||
}
|
||||
var n int
|
||||
// Write all remaining data from the current buffer
|
||||
n, err := w.Write(b)
|
||||
written += int64(n)
|
||||
updateCRC(b)
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
d.dataOffsets.currOff = 0
|
||||
// We've read all the data from this message.
|
||||
if d.dataOffsets.currBuf == d.dataOffsets.endBuf {
|
||||
d.done = true
|
||||
d.databufs.Free()
|
||||
} else {
|
||||
d.dataOffsets.currBuf++
|
||||
}
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// Consume the next available tag in the input data and return the field number and type.
|
||||
// Advances the relevant offsets in the data.
|
||||
func (d *readObjectResponseDecoder) consumeTag() (protowire.Number, protowire.Type, error) {
|
||||
tagBuf := d.peek()
|
||||
|
||||
// Consume the next tag. This will tell us which field is next in the
|
||||
// buffer, its type, and how much space it takes up.
|
||||
fieldNum, fieldType, tagLength := protowire.ConsumeTag(tagBuf)
|
||||
if tagLength < 0 {
|
||||
return 0, 0, protowire.ParseError(tagLength)
|
||||
}
|
||||
// Update the offsets and current buffer depending on the tag length.
|
||||
if err := d.advanceOffset(uint64(tagLength)); err != nil {
|
||||
return 0, 0, fmt.Errorf("consuming tag: %w", err)
|
||||
}
|
||||
return fieldNum, fieldType, nil
|
||||
}
|
||||
|
||||
// Consume a varint that represents the length of a bytes field. Return the length of
|
||||
// the data, and advance the offsets by the length of the varint.
|
||||
func (d *readObjectResponseDecoder) consumeVarint() (uint64, error) {
|
||||
tagBuf := d.peek()
|
||||
|
||||
// Consume the next tag. This will tell us which field is next in the
|
||||
// buffer, its type, and how much space it takes up.
|
||||
dataLength, tagLength := protowire.ConsumeVarint(tagBuf)
|
||||
if tagLength < 0 {
|
||||
return 0, protowire.ParseError(tagLength)
|
||||
}
|
||||
|
||||
// Update the offsets and current buffer depending on the tag length.
|
||||
d.advanceOffset(uint64(tagLength))
|
||||
return dataLength, nil
|
||||
}
|
||||
|
||||
func (d *readObjectResponseDecoder) consumeFixed32() (uint32, error) {
|
||||
valueBuf := d.peek()
|
||||
|
||||
// Consume the next tag. This will tell us which field is next in the
|
||||
// buffer, its type, and how much space it takes up.
|
||||
value, tagLength := protowire.ConsumeFixed32(valueBuf)
|
||||
if tagLength < 0 {
|
||||
return 0, protowire.ParseError(tagLength)
|
||||
}
|
||||
|
||||
// Update the offsets and current buffer depending on the tag length.
|
||||
d.advanceOffset(uint64(tagLength))
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (d *readObjectResponseDecoder) consumeFixed64() (uint64, error) {
|
||||
valueBuf := d.peek()
|
||||
|
||||
// Consume the next tag. This will tell us which field is next in the
|
||||
// buffer, its type, and how much space it takes up.
|
||||
value, tagLength := protowire.ConsumeFixed64(valueBuf)
|
||||
if tagLength < 0 {
|
||||
return 0, protowire.ParseError(tagLength)
|
||||
}
|
||||
|
||||
// Update the offsets and current buffer depending on the tag length.
|
||||
d.advanceOffset(uint64(tagLength))
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Consume any field values up to the end offset provided and don't return anything.
|
||||
// This is used to skip any values which are not going to be used.
|
||||
// msgEndOff is indexed in terms of the overall data across all buffers.
|
||||
func (d *readObjectResponseDecoder) consumeFieldValue(fieldNum protowire.Number, fieldType protowire.Type) error {
|
||||
// reimplement protowire.ConsumeFieldValue without the extra case for groups (which
|
||||
// are are complicted and not a thing in proto3).
|
||||
var err error
|
||||
switch fieldType {
|
||||
case protowire.VarintType:
|
||||
_, err = d.consumeVarint()
|
||||
case protowire.Fixed32Type:
|
||||
_, err = d.consumeFixed32()
|
||||
case protowire.Fixed64Type:
|
||||
_, err = d.consumeFixed64()
|
||||
case protowire.BytesType:
|
||||
_, err = d.consumeBytes()
|
||||
default:
|
||||
return fmt.Errorf("unknown field type %v in field %v", fieldType, fieldNum)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("consuming field %v of type %v: %w", fieldNum, fieldType, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Consume a bytes field from the input. Returns offsets for the data in the buffer slices
|
||||
// and an error.
|
||||
func (d *readObjectResponseDecoder) consumeBytes() (bufferSliceOffsetsReadObject, error) {
|
||||
// m is the length of the data past the tag.
|
||||
m, err := d.consumeVarint()
|
||||
if err != nil {
|
||||
return bufferSliceOffsetsReadObject{}, fmt.Errorf("consuming bytes field: %w", err)
|
||||
}
|
||||
offsets := bufferSliceOffsetsReadObject{
|
||||
startBuf: d.currBuf,
|
||||
startOff: d.currOff,
|
||||
currBuf: d.currBuf,
|
||||
currOff: d.currOff,
|
||||
}
|
||||
|
||||
// Advance offsets to lengths of bytes field and capture where we end.
|
||||
d.advanceOffset(m)
|
||||
offsets.endBuf = d.currBuf
|
||||
offsets.endOff = d.currOff
|
||||
return offsets, nil
|
||||
}
|
||||
|
||||
// Consume a bytes field from the input and copy into a new buffer if
|
||||
// necessary (if the data is split across buffers in databuf). This can be
|
||||
// used to leverage proto.Unmarshal for small bytes fields (i.e. anything
|
||||
// except object data).
|
||||
func (d *readObjectResponseDecoder) consumeBytesCopy() ([]byte, error) {
|
||||
// m is the length of the bytes data.
|
||||
m, err := d.consumeVarint()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("consuming varint: %w", err)
|
||||
}
|
||||
// Copy the data into a buffer and advance the offset
|
||||
b := d.copyNextBytes(int(m))
|
||||
if err := d.advanceOffset(m); err != nil {
|
||||
return nil, fmt.Errorf("advancing offset: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// readFullObjectResponse returns the ReadObjectResponse that is encoded in the
|
||||
// wire-encoded message buffer b, or an error if the message is invalid.
|
||||
// This must be used on the first recv of an object as it may contain all fields
|
||||
// of ReadObjectResponse, and we use or pass on those fields to the user.
|
||||
// This function is essentially identical to proto.Unmarshal, except it aliases
|
||||
// the data in the input []byte. If the proto library adds a feature to
|
||||
// Unmarshal that does that, this function can be dropped.
|
||||
func (d *readObjectResponseDecoder) readFullObjectResponse() error {
|
||||
msg := &storagepb.ReadObjectResponse{}
|
||||
|
||||
// Loop over the entire message, extracting fields as we go. This does not
|
||||
// handle field concatenation, in which the contents of a single field
|
||||
// are split across multiple protobuf tags.
|
||||
for d.off < uint64(d.databufs.Len()) {
|
||||
fieldNum, fieldType, err := d.consumeTag()
|
||||
if err != nil {
|
||||
return fmt.Errorf("consuming next tag: %w", err)
|
||||
}
|
||||
|
||||
// Unmarshal the field according to its type. Only fields that are not
|
||||
// nil will be present.
|
||||
switch {
|
||||
case fieldNum == checksummedDataFieldReadObject && fieldType == protowire.BytesType:
|
||||
// The ChecksummedData field was found. Initialize the struct.
|
||||
msg.ChecksummedData = &storagepb.ChecksummedData{}
|
||||
|
||||
bytesFieldLen, err := d.consumeVarint()
|
||||
if err != nil {
|
||||
return fmt.Errorf("consuming bytes: %v", err)
|
||||
}
|
||||
|
||||
var contentEndOff = d.off + bytesFieldLen
|
||||
for d.off < contentEndOff {
|
||||
gotNum, gotTyp, err := d.consumeTag()
|
||||
if err != nil {
|
||||
return fmt.Errorf("consuming checksummedData tag: %w", err)
|
||||
}
|
||||
|
||||
switch {
|
||||
case gotNum == checksummedDataContentFieldReadObject && gotTyp == protowire.BytesType:
|
||||
// Get the offsets of the content bytes.
|
||||
d.dataOffsets, err = d.consumeBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ReadObjectResponse.ChecksummedData.Content: %w", err)
|
||||
}
|
||||
case gotNum == checksummedDataCRC32CFieldReadObject && gotTyp == protowire.Fixed32Type:
|
||||
v, err := d.consumeFixed32()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ReadObjectResponse.ChecksummedData.Crc32C: %w", err)
|
||||
}
|
||||
msg.ChecksummedData.Crc32C = &v
|
||||
default:
|
||||
err := d.consumeFieldValue(gotNum, gotTyp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid field in ReadObjectResponse.ChecksummedData: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case fieldNum == objectChecksumsFieldReadObject && fieldType == protowire.BytesType:
|
||||
// The field was found. Initialize the struct.
|
||||
msg.ObjectChecksums = &storagepb.ObjectChecksums{}
|
||||
// Consume the bytes and copy them into a single buffer if they are split across buffers.
|
||||
buf, err := d.consumeBytesCopy()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ReadObjectResponse.ObjectChecksums: %v", err)
|
||||
}
|
||||
// Unmarshal.
|
||||
if err := proto.Unmarshal(buf, msg.ObjectChecksums); err != nil {
|
||||
return err
|
||||
}
|
||||
case fieldNum == contentRangeFieldReadObject && fieldType == protowire.BytesType:
|
||||
msg.ContentRange = &storagepb.ContentRange{}
|
||||
buf, err := d.consumeBytesCopy()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ReadObjectResponse.ContentRange: %v", err)
|
||||
}
|
||||
if err := proto.Unmarshal(buf, msg.ContentRange); err != nil {
|
||||
return err
|
||||
}
|
||||
case fieldNum == metadataFieldReadObject && fieldType == protowire.BytesType:
|
||||
msg.Metadata = &storagepb.Object{}
|
||||
|
||||
buf, err := d.consumeBytesCopy()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ReadObjectResponse.Metadata: %v", err)
|
||||
}
|
||||
|
||||
if err := proto.Unmarshal(buf, msg.Metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
err := d.consumeFieldValue(fieldNum, fieldType)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid field in ReadObjectResponse: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
d.msg = msg
|
||||
return nil
|
||||
}
|
||||
|
||||
// reopenStream "closes" the existing stream and attempts to reopen a stream and
|
||||
// sets the Reader's stream and cancelStream properties in the process.
|
||||
func (r *gRPCReadObjectReader) reopenStream() error {
|
||||
// Close existing stream and initialize new stream with updated offset.
|
||||
r.Close()
|
||||
|
||||
res, cancel, err := r.reopen(r.seen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.stream = res.stream
|
||||
r.currMsg = res.decoder
|
||||
r.cancel = cancel
|
||||
return nil
|
||||
}
|
||||
+305
@@ -0,0 +1,305 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
gapic "cloud.google.com/go/storage/internal/apiv2"
|
||||
"cloud.google.com/go/storage/internal/apiv2/storagepb"
|
||||
gax "github.com/googleapis/gax-go/v2"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type gRPCAppendBidiWriteBufferSender struct {
|
||||
ctx context.Context
|
||||
bucket string
|
||||
routingToken *string
|
||||
raw *gapic.Client
|
||||
settings *settings
|
||||
stream storagepb.Storage_BidiWriteObjectClient
|
||||
firstMessage *storagepb.BidiWriteObjectRequest
|
||||
objectChecksums *storagepb.ObjectChecksums
|
||||
|
||||
forceFirstMessage bool
|
||||
flushOffset int64
|
||||
|
||||
// Fields used to report responses from the receive side of the stream
|
||||
// recvs is closed when the current recv goroutine is complete. recvErr is set
|
||||
// to the result of that stream (including io.EOF to indicate success)
|
||||
recvs <-chan *storagepb.BidiWriteObjectResponse
|
||||
recvErr error
|
||||
}
|
||||
|
||||
func (w *gRPCWriter) newGRPCAppendBidiWriteBufferSender() (*gRPCAppendBidiWriteBufferSender, error) {
|
||||
s := &gRPCAppendBidiWriteBufferSender{
|
||||
ctx: w.ctx,
|
||||
bucket: w.spec.GetResource().GetBucket(),
|
||||
raw: w.c.raw,
|
||||
settings: w.c.settings,
|
||||
firstMessage: &storagepb.BidiWriteObjectRequest{
|
||||
FirstMessage: &storagepb.BidiWriteObjectRequest_WriteObjectSpec{
|
||||
WriteObjectSpec: w.spec,
|
||||
},
|
||||
CommonObjectRequestParams: toProtoCommonObjectRequestParams(w.encryptionKey),
|
||||
},
|
||||
objectChecksums: toProtoChecksums(w.sendCRC32C, w.attrs),
|
||||
forceFirstMessage: true,
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) connect() (err error) {
|
||||
err = func() error {
|
||||
// If this is a forced first message, we've already determined it's safe to
|
||||
// send.
|
||||
if s.forceFirstMessage {
|
||||
s.forceFirstMessage = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// It's always ok to reconnect if there is a handle. This is the common
|
||||
// case.
|
||||
if s.firstMessage.GetAppendObjectSpec().GetWriteHandle() != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We can also reconnect if the first message has an if_generation_match or
|
||||
// if_metageneration_match condition. Note that negative conditions like
|
||||
// if_generation_not_match are not necessarily safe to retry.
|
||||
aos := s.firstMessage.GetAppendObjectSpec()
|
||||
wos := s.firstMessage.GetWriteObjectSpec()
|
||||
|
||||
if aos != nil && aos.IfMetagenerationMatch != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if wos != nil && wos.IfGenerationMatch != nil {
|
||||
return nil
|
||||
}
|
||||
if wos != nil && wos.IfMetagenerationMatch != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise, it is not safe to reconnect.
|
||||
return errors.New("cannot safely reconnect; no write handle or preconditions")
|
||||
}()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.startReceiver()
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) withRequestParams(ctx context.Context) context.Context {
|
||||
param := fmt.Sprintf("appendable=true&bucket=%s", s.bucket)
|
||||
if s.routingToken != nil {
|
||||
param = param + fmt.Sprintf("&routing_token=%s", *s.routingToken)
|
||||
}
|
||||
return gax.InsertMetadataIntoOutgoingContext(s.ctx, "x-goog-request-params", param)
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) startReceiver() (err error) {
|
||||
s.stream, err = s.raw.BidiWriteObject(s.withRequestParams(s.ctx), s.settings.gax...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
recvs := make(chan *storagepb.BidiWriteObjectResponse)
|
||||
s.recvs = recvs
|
||||
s.recvErr = nil
|
||||
go s.receiveMessages(recvs)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) ensureFirstMessageAppendObjectSpec() {
|
||||
if s.firstMessage.GetWriteObjectSpec() != nil {
|
||||
w := s.firstMessage.GetWriteObjectSpec()
|
||||
s.firstMessage.FirstMessage = &storagepb.BidiWriteObjectRequest_AppendObjectSpec{
|
||||
AppendObjectSpec: &storagepb.AppendObjectSpec{
|
||||
Bucket: w.GetResource().GetBucket(),
|
||||
Object: w.GetResource().GetName(),
|
||||
IfMetagenerationMatch: w.IfMetagenerationMatch,
|
||||
IfMetagenerationNotMatch: w.IfMetagenerationNotMatch,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) maybeUpdateFirstMessage(resp *storagepb.BidiWriteObjectResponse) {
|
||||
// Any affirmative response should switch us to an AppendObjectSpec.
|
||||
s.ensureFirstMessageAppendObjectSpec()
|
||||
|
||||
if r := resp.GetResource(); r != nil {
|
||||
aos := s.firstMessage.GetAppendObjectSpec()
|
||||
aos.Bucket = r.GetBucket()
|
||||
aos.Object = r.GetName()
|
||||
aos.Generation = r.GetGeneration()
|
||||
}
|
||||
|
||||
if h := resp.GetWriteHandle(); h != nil {
|
||||
s.firstMessage.GetAppendObjectSpec().WriteHandle = h
|
||||
}
|
||||
}
|
||||
|
||||
type bidiWriteObjectRedirectionError struct{}
|
||||
|
||||
func (e bidiWriteObjectRedirectionError) Error() string {
|
||||
return "BidiWriteObjectRedirectedError"
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) handleRedirectionError(e *storagepb.BidiWriteObjectRedirectedError) bool {
|
||||
if e.RoutingToken == nil {
|
||||
// This shouldn't happen, but we don't want to blindly retry here. Instead,
|
||||
// surface the error to the caller.
|
||||
return false
|
||||
}
|
||||
|
||||
if e.WriteHandle != nil {
|
||||
// If we get back a write handle, we should use it. We can only use it
|
||||
// on an append object spec.
|
||||
s.ensureFirstMessageAppendObjectSpec()
|
||||
s.firstMessage.GetAppendObjectSpec().WriteHandle = e.WriteHandle
|
||||
// Generation is meant to only come with the WriteHandle, so ignore it
|
||||
// otherwise.
|
||||
if e.Generation != nil {
|
||||
s.firstMessage.GetAppendObjectSpec().Generation = e.GetGeneration()
|
||||
}
|
||||
}
|
||||
|
||||
s.routingToken = e.RoutingToken
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) receiveMessages(resps chan<- *storagepb.BidiWriteObjectResponse) {
|
||||
resp, err := s.stream.Recv()
|
||||
for err == nil {
|
||||
s.maybeUpdateFirstMessage(resp)
|
||||
|
||||
if resp.WriteStatus != nil {
|
||||
// We only get a WriteStatus if this was a solicited message (either
|
||||
// state_lookup: true or finish_write: true). Unsolicited messages may
|
||||
// arrive to update our handle if necessary. We don't want to block on
|
||||
// this channel write if this was an unsolicited message.
|
||||
resps <- resp
|
||||
}
|
||||
|
||||
resp, err = s.stream.Recv()
|
||||
}
|
||||
|
||||
if st, ok := status.FromError(err); ok && st.Code() == codes.Aborted {
|
||||
for _, d := range st.Details() {
|
||||
if e, ok := d.(*storagepb.BidiWriteObjectRedirectedError); ok {
|
||||
// If we can handle this error, replace it with the sentinel. Otherwise,
|
||||
// report it to the user.
|
||||
if ok := s.handleRedirectionError(e); ok {
|
||||
err = bidiWriteObjectRedirectionError{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: automatically reconnect on retriable recv errors, even if there are
|
||||
// no sends occurring.
|
||||
s.recvErr = err
|
||||
close(resps)
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) sendOnConnectedStream(buf []byte, offset int64, flush, finishWrite, sendFirstMessage bool) (obj *storagepb.Object, err error) {
|
||||
req := bidiWriteObjectRequest(buf, offset, flush, finishWrite)
|
||||
if finishWrite {
|
||||
// appendable objects pass checksums on the last message only
|
||||
req.ObjectChecksums = s.objectChecksums
|
||||
}
|
||||
if sendFirstMessage {
|
||||
proto.Merge(req, s.firstMessage)
|
||||
}
|
||||
|
||||
if err = s.stream.Send(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if finishWrite {
|
||||
s.stream.CloseSend()
|
||||
for resp := range s.recvs {
|
||||
if resp.GetResource() != nil {
|
||||
obj = resp.GetResource()
|
||||
}
|
||||
}
|
||||
if s.recvErr != io.EOF {
|
||||
return nil, s.recvErr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if flush {
|
||||
// We don't necessarily expect multiple responses for a single flush, but
|
||||
// this allows the server to send multiple responses if it wants to.
|
||||
for s.flushOffset < offset+int64(len(buf)) {
|
||||
resp, ok := <-s.recvs
|
||||
if !ok {
|
||||
return nil, s.recvErr
|
||||
}
|
||||
pSize := resp.GetPersistedSize()
|
||||
rSize := resp.GetResource().GetSize()
|
||||
if s.flushOffset < pSize {
|
||||
s.flushOffset = pSize
|
||||
}
|
||||
if s.flushOffset < rSize {
|
||||
s.flushOffset = rSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *gRPCAppendBidiWriteBufferSender) sendBuffer(buf []byte, offset int64, flush, finishWrite bool) (obj *storagepb.Object, err error) {
|
||||
for {
|
||||
sendFirstMessage := false
|
||||
if s.stream == nil {
|
||||
sendFirstMessage = true
|
||||
if err = s.connect(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
obj, err = s.sendOnConnectedStream(buf, offset, flush, finishWrite, sendFirstMessage)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// await recv stream termination
|
||||
for range s.recvs {
|
||||
}
|
||||
if s.recvErr != io.EOF {
|
||||
err = s.recvErr
|
||||
}
|
||||
s.stream = nil
|
||||
|
||||
// Retry transparently on a redirection error
|
||||
if _, ok := err.(bidiWriteObjectRedirectionError); ok {
|
||||
s.forceFirstMessage = true
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
+55
-8
@@ -592,6 +592,31 @@ func (c *httpStorageClient) RestoreObject(ctx context.Context, params *restoreOb
|
||||
return newObject(obj), err
|
||||
}
|
||||
|
||||
func (c *httpStorageClient) MoveObject(ctx context.Context, params *moveObjectParams, opts ...storageOption) (*ObjectAttrs, error) {
|
||||
s := callSettings(c.settings, opts...)
|
||||
req := c.raw.Objects.Move(params.bucket, params.srcObject, params.dstObject).Context(ctx)
|
||||
if err := applyConds("MoveObjectDestination", defaultGen, params.dstConds, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := applySourceConds("MoveObjectSource", defaultGen, params.srcConds, req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.userProject != "" {
|
||||
req.UserProject(s.userProject)
|
||||
}
|
||||
if err := setEncryptionHeaders(req.Header(), params.encryptionKey, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var obj *raw.Object
|
||||
var err error
|
||||
err = run(ctx, func(ctx context.Context) error { obj, err = req.Context(ctx).Do(); return err }, s.retry, s.idempotent)
|
||||
var e *googleapi.Error
|
||||
if ok := errors.As(err, &e); ok && e.Code == http.StatusNotFound {
|
||||
return nil, ErrObjectNotExist
|
||||
}
|
||||
return newObject(obj), err
|
||||
}
|
||||
|
||||
// Default Object ACL methods.
|
||||
|
||||
func (c *httpStorageClient) DeleteDefaultObjectACL(ctx context.Context, bucket string, entity ACLEntity, opts ...storageOption) error {
|
||||
@@ -797,7 +822,7 @@ func (c *httpStorageClient) RewriteObject(ctx context.Context, req *rewriteObjec
|
||||
if err := applyConds("Copy destination", defaultGen, req.dstObject.conds, call); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := applySourceConds(req.srcObject.gen, req.srcObject.conds, call); err != nil {
|
||||
if err := applySourceConds("Copy source", req.srcObject.gen, req.srcObject.conds, call); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.userProject != "" {
|
||||
@@ -836,6 +861,11 @@ func (c *httpStorageClient) RewriteObject(ctx context.Context, req *rewriteObjec
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// NewMultiRangeDownloader is not supported by http client.
|
||||
func (c *httpStorageClient) NewMultiRangeDownloader(ctx context.Context, params *newMultiRangeDownloaderParams, opts ...storageOption) (mr *MultiRangeDownloader, err error) {
|
||||
return nil, errMethodNotSupported
|
||||
}
|
||||
|
||||
func (c *httpStorageClient) NewRangeReader(ctx context.Context, params *newRangeReaderParams, opts ...storageOption) (r *Reader, err error) {
|
||||
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.httpStorageClient.NewRangeReader")
|
||||
defer func() { trace.EndSpan(ctx, err) }()
|
||||
@@ -901,11 +931,12 @@ func (c *httpStorageClient) newRangeReaderXML(ctx context.Context, params *newRa
|
||||
done <- true
|
||||
}()
|
||||
|
||||
// Wait until timeout or request is successful.
|
||||
timer := time.After(c.dynamicReadReqStallTimeout.getValue(params.bucket))
|
||||
// Wait until stall timeout or request is successful.
|
||||
stallTimeout := c.dynamicReadReqStallTimeout.getValue(params.bucket)
|
||||
timer := time.After(stallTimeout)
|
||||
select {
|
||||
case <-timer:
|
||||
log.Printf("stalled read-req cancelled after %fs", c.dynamicReadReqStallTimeout.getValue(params.bucket).Seconds())
|
||||
log.Printf("stalled read-req (%p) cancelled after %fs", req, stallTimeout.Seconds())
|
||||
cancel()
|
||||
err = context.DeadlineExceeded
|
||||
if res != nil && res.Body != nil {
|
||||
@@ -951,6 +982,10 @@ func (c *httpStorageClient) newRangeReaderJSON(ctx context.Context, params *newR
|
||||
}
|
||||
|
||||
func (c *httpStorageClient) OpenWriter(params *openWriterParams, opts ...storageOption) (*io.PipeWriter, error) {
|
||||
if params.append {
|
||||
return nil, errors.New("storage: append not supported on HTTP Client; use gRPC")
|
||||
}
|
||||
|
||||
s := callSettings(c.settings, opts...)
|
||||
errorf := params.setError
|
||||
setObj := params.setObj
|
||||
@@ -966,6 +1001,9 @@ func (c *httpStorageClient) OpenWriter(params *openWriterParams, opts ...storage
|
||||
if params.chunkRetryDeadline != 0 {
|
||||
mediaOpts = append(mediaOpts, googleapi.ChunkRetryDeadline(params.chunkRetryDeadline))
|
||||
}
|
||||
if params.chunkTransferTimeout != 0 {
|
||||
mediaOpts = append(mediaOpts, googleapi.ChunkTransferTimeout(params.chunkTransferTimeout))
|
||||
}
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
|
||||
@@ -1512,6 +1550,14 @@ func parseReadResponse(res *http.Response, params *newRangeReaderParams, reopen
|
||||
}
|
||||
}
|
||||
|
||||
metadata := map[string]string{}
|
||||
for key, values := range res.Header {
|
||||
if len(values) > 0 && strings.HasPrefix(key, "X-Goog-Meta-") {
|
||||
key := key[len("X-Goog-Meta-"):]
|
||||
metadata[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
attrs := ReaderObjectAttrs{
|
||||
Size: size,
|
||||
ContentType: res.Header.Get("Content-Type"),
|
||||
@@ -1525,10 +1571,11 @@ func parseReadResponse(res *http.Response, params *newRangeReaderParams, reopen
|
||||
Decompressed: res.Uncompressed || uncompressedByServer(res),
|
||||
}
|
||||
return &Reader{
|
||||
Attrs: attrs,
|
||||
size: size,
|
||||
remain: remain,
|
||||
checkCRC: checkCRC,
|
||||
Attrs: attrs,
|
||||
objectMetadata: &metadata,
|
||||
size: size,
|
||||
remain: remain,
|
||||
checkCRC: checkCRC,
|
||||
reader: &httpReader{
|
||||
reopen: reopen,
|
||||
body: body,
|
||||
|
||||
+3
-97
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Google LLC
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -41,7 +41,7 @@ type BucketIterator struct {
|
||||
InternalFetch func(pageSize int, pageToken string) (results []*storagepb.Bucket, nextPageToken string, err error)
|
||||
}
|
||||
|
||||
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||
// PageInfo supports pagination. See the [google.golang.org/api/iterator] package for details.
|
||||
func (it *BucketIterator) PageInfo() *iterator.PageInfo {
|
||||
return it.pageInfo
|
||||
}
|
||||
@@ -68,100 +68,6 @@ func (it *BucketIterator) takeBuf() interface{} {
|
||||
return b
|
||||
}
|
||||
|
||||
// HmacKeyMetadataIterator manages a stream of *storagepb.HmacKeyMetadata.
|
||||
type HmacKeyMetadataIterator struct {
|
||||
items []*storagepb.HmacKeyMetadata
|
||||
pageInfo *iterator.PageInfo
|
||||
nextFunc func() error
|
||||
|
||||
// Response is the raw response for the current page.
|
||||
// It must be cast to the RPC response type.
|
||||
// Calling Next() or InternalFetch() updates this value.
|
||||
Response interface{}
|
||||
|
||||
// InternalFetch is for use by the Google Cloud Libraries only.
|
||||
// It is not part of the stable interface of this package.
|
||||
//
|
||||
// InternalFetch returns results from a single call to the underlying RPC.
|
||||
// The number of results is no greater than pageSize.
|
||||
// If there are no more results, nextPageToken is empty and err is nil.
|
||||
InternalFetch func(pageSize int, pageToken string) (results []*storagepb.HmacKeyMetadata, nextPageToken string, err error)
|
||||
}
|
||||
|
||||
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||
func (it *HmacKeyMetadataIterator) PageInfo() *iterator.PageInfo {
|
||||
return it.pageInfo
|
||||
}
|
||||
|
||||
// Next returns the next result. Its second return value is iterator.Done if there are no more
|
||||
// results. Once Next returns Done, all subsequent calls will return Done.
|
||||
func (it *HmacKeyMetadataIterator) Next() (*storagepb.HmacKeyMetadata, error) {
|
||||
var item *storagepb.HmacKeyMetadata
|
||||
if err := it.nextFunc(); err != nil {
|
||||
return item, err
|
||||
}
|
||||
item = it.items[0]
|
||||
it.items = it.items[1:]
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (it *HmacKeyMetadataIterator) bufLen() int {
|
||||
return len(it.items)
|
||||
}
|
||||
|
||||
func (it *HmacKeyMetadataIterator) takeBuf() interface{} {
|
||||
b := it.items
|
||||
it.items = nil
|
||||
return b
|
||||
}
|
||||
|
||||
// NotificationConfigIterator manages a stream of *storagepb.NotificationConfig.
|
||||
type NotificationConfigIterator struct {
|
||||
items []*storagepb.NotificationConfig
|
||||
pageInfo *iterator.PageInfo
|
||||
nextFunc func() error
|
||||
|
||||
// Response is the raw response for the current page.
|
||||
// It must be cast to the RPC response type.
|
||||
// Calling Next() or InternalFetch() updates this value.
|
||||
Response interface{}
|
||||
|
||||
// InternalFetch is for use by the Google Cloud Libraries only.
|
||||
// It is not part of the stable interface of this package.
|
||||
//
|
||||
// InternalFetch returns results from a single call to the underlying RPC.
|
||||
// The number of results is no greater than pageSize.
|
||||
// If there are no more results, nextPageToken is empty and err is nil.
|
||||
InternalFetch func(pageSize int, pageToken string) (results []*storagepb.NotificationConfig, nextPageToken string, err error)
|
||||
}
|
||||
|
||||
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||
func (it *NotificationConfigIterator) PageInfo() *iterator.PageInfo {
|
||||
return it.pageInfo
|
||||
}
|
||||
|
||||
// Next returns the next result. Its second return value is iterator.Done if there are no more
|
||||
// results. Once Next returns Done, all subsequent calls will return Done.
|
||||
func (it *NotificationConfigIterator) Next() (*storagepb.NotificationConfig, error) {
|
||||
var item *storagepb.NotificationConfig
|
||||
if err := it.nextFunc(); err != nil {
|
||||
return item, err
|
||||
}
|
||||
item = it.items[0]
|
||||
it.items = it.items[1:]
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func (it *NotificationConfigIterator) bufLen() int {
|
||||
return len(it.items)
|
||||
}
|
||||
|
||||
func (it *NotificationConfigIterator) takeBuf() interface{} {
|
||||
b := it.items
|
||||
it.items = nil
|
||||
return b
|
||||
}
|
||||
|
||||
// ObjectIterator manages a stream of *storagepb.Object.
|
||||
type ObjectIterator struct {
|
||||
items []*storagepb.Object
|
||||
@@ -182,7 +88,7 @@ type ObjectIterator struct {
|
||||
InternalFetch func(pageSize int, pageToken string) (results []*storagepb.Object, nextPageToken string, err error)
|
||||
}
|
||||
|
||||
// PageInfo supports pagination. See the google.golang.org/api/iterator package for details.
|
||||
// PageInfo supports pagination. See the [google.golang.org/api/iterator] package for details.
|
||||
func (it *ObjectIterator) PageInfo() *iterator.PageInfo {
|
||||
return it.pageInfo
|
||||
}
|
||||
|
||||
+1
-13
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Google LLC
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -31,18 +31,6 @@ func (it *BucketIterator) All() iter.Seq2[*storagepb.Bucket, error] {
|
||||
return iterator.RangeAdapter(it.Next)
|
||||
}
|
||||
|
||||
// All returns an iterator. If an error is returned by the iterator, the
|
||||
// iterator will stop after that iteration.
|
||||
func (it *HmacKeyMetadataIterator) All() iter.Seq2[*storagepb.HmacKeyMetadata, error] {
|
||||
return iterator.RangeAdapter(it.Next)
|
||||
}
|
||||
|
||||
// All returns an iterator. If an error is returned by the iterator, the
|
||||
// iterator will stop after that iteration.
|
||||
func (it *NotificationConfigIterator) All() iter.Seq2[*storagepb.NotificationConfig, error] {
|
||||
return iterator.RangeAdapter(it.Next)
|
||||
}
|
||||
|
||||
// All returns an iterator. If an error is returned by the iterator, the
|
||||
// iterator will stop after that iteration.
|
||||
func (it *ObjectIterator) All() iter.Seq2[*storagepb.Object, error] {
|
||||
|
||||
+5
-46
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Google LLC
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,7 @@
|
||||
//
|
||||
// To get started with this package, create a client.
|
||||
//
|
||||
// // go get cloud.google.com/go/storage/internal/apiv2@latest
|
||||
// ctx := context.Background()
|
||||
// // This snippet has been automatically generated and should be regarded as a code template only.
|
||||
// // It will require modifications to work:
|
||||
@@ -61,25 +62,14 @@
|
||||
//
|
||||
// # Using the Client
|
||||
//
|
||||
// The following is an example of making an API call with the newly created client.
|
||||
// The following is an example of making an API call with the newly created client, mentioned above.
|
||||
//
|
||||
// ctx := context.Background()
|
||||
// // This snippet has been automatically generated and should be regarded as a code template only.
|
||||
// // It will require modifications to work:
|
||||
// // - It may require correct/in-range values for request initialization.
|
||||
// // - It may require specifying regional endpoints when creating the service client as shown in:
|
||||
// // https://pkg.go.dev/cloud.google.com/go#hdr-Client_Options
|
||||
// c, err := storage.NewClient(ctx)
|
||||
// if err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// defer c.Close()
|
||||
// stream, err := c.BidiWriteObject(ctx)
|
||||
// stream, err := c.BidiReadObject(ctx)
|
||||
// if err != nil {
|
||||
// // TODO: Handle error.
|
||||
// }
|
||||
// go func() {
|
||||
// reqs := []*storagepb.BidiWriteObjectRequest{
|
||||
// reqs := []*storagepb.BidiReadObjectRequest{
|
||||
// // TODO: Create requests.
|
||||
// }
|
||||
// for _, req := range reqs {
|
||||
@@ -115,34 +105,3 @@
|
||||
// [Debugging Client Libraries]: https://pkg.go.dev/cloud.google.com/go#hdr-Debugging
|
||||
// [Inspecting errors]: https://pkg.go.dev/cloud.google.com/go#hdr-Inspecting_errors
|
||||
package storage // import "cloud.google.com/go/storage/internal/apiv2"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
// For more information on implementing a client constructor hook, see
|
||||
// https://github.com/googleapis/google-cloud-go/wiki/Customizing-constructors.
|
||||
type clientHookParams struct{}
|
||||
type clientHook func(context.Context, clientHookParams) ([]option.ClientOption, error)
|
||||
|
||||
var versionClient string
|
||||
|
||||
func getVersionClient() string {
|
||||
if versionClient == "" {
|
||||
return "UNKNOWN"
|
||||
}
|
||||
return versionClient
|
||||
}
|
||||
|
||||
// DefaultAuthScopes reports the default set of authentication scopes to use with this package.
|
||||
func DefaultAuthScopes() []string {
|
||||
return []string{
|
||||
"https://www.googleapis.com/auth/cloud-platform",
|
||||
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||
"https://www.googleapis.com/auth/devstorage.read_write",
|
||||
}
|
||||
}
|
||||
+10
-50
@@ -10,6 +10,11 @@
|
||||
"grpc": {
|
||||
"libraryClient": "Client",
|
||||
"rpcs": {
|
||||
"BidiReadObject": {
|
||||
"methods": [
|
||||
"BidiReadObject"
|
||||
]
|
||||
},
|
||||
"BidiWriteObject": {
|
||||
"methods": [
|
||||
"BidiWriteObject"
|
||||
@@ -30,31 +35,11 @@
|
||||
"CreateBucket"
|
||||
]
|
||||
},
|
||||
"CreateHmacKey": {
|
||||
"methods": [
|
||||
"CreateHmacKey"
|
||||
]
|
||||
},
|
||||
"CreateNotificationConfig": {
|
||||
"methods": [
|
||||
"CreateNotificationConfig"
|
||||
]
|
||||
},
|
||||
"DeleteBucket": {
|
||||
"methods": [
|
||||
"DeleteBucket"
|
||||
]
|
||||
},
|
||||
"DeleteHmacKey": {
|
||||
"methods": [
|
||||
"DeleteHmacKey"
|
||||
]
|
||||
},
|
||||
"DeleteNotificationConfig": {
|
||||
"methods": [
|
||||
"DeleteNotificationConfig"
|
||||
]
|
||||
},
|
||||
"DeleteObject": {
|
||||
"methods": [
|
||||
"DeleteObject"
|
||||
@@ -65,46 +50,21 @@
|
||||
"GetBucket"
|
||||
]
|
||||
},
|
||||
"GetHmacKey": {
|
||||
"methods": [
|
||||
"GetHmacKey"
|
||||
]
|
||||
},
|
||||
"GetIamPolicy": {
|
||||
"methods": [
|
||||
"GetIamPolicy"
|
||||
]
|
||||
},
|
||||
"GetNotificationConfig": {
|
||||
"methods": [
|
||||
"GetNotificationConfig"
|
||||
]
|
||||
},
|
||||
"GetObject": {
|
||||
"methods": [
|
||||
"GetObject"
|
||||
]
|
||||
},
|
||||
"GetServiceAccount": {
|
||||
"methods": [
|
||||
"GetServiceAccount"
|
||||
]
|
||||
},
|
||||
"ListBuckets": {
|
||||
"methods": [
|
||||
"ListBuckets"
|
||||
]
|
||||
},
|
||||
"ListHmacKeys": {
|
||||
"methods": [
|
||||
"ListHmacKeys"
|
||||
]
|
||||
},
|
||||
"ListNotificationConfigs": {
|
||||
"methods": [
|
||||
"ListNotificationConfigs"
|
||||
]
|
||||
},
|
||||
"ListObjects": {
|
||||
"methods": [
|
||||
"ListObjects"
|
||||
@@ -115,6 +75,11 @@
|
||||
"LockBucketRetentionPolicy"
|
||||
]
|
||||
},
|
||||
"MoveObject": {
|
||||
"methods": [
|
||||
"MoveObject"
|
||||
]
|
||||
},
|
||||
"QueryWriteStatus": {
|
||||
"methods": [
|
||||
"QueryWriteStatus"
|
||||
@@ -155,11 +120,6 @@
|
||||
"UpdateBucket"
|
||||
]
|
||||
},
|
||||
"UpdateHmacKey": {
|
||||
"methods": [
|
||||
"UpdateHmacKey"
|
||||
]
|
||||
},
|
||||
"UpdateObject": {
|
||||
"methods": [
|
||||
"UpdateObject"
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// Code generated by protoc-gen-go_gapic. DO NOT EDIT.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/googleapis/gax-go/v2/internallog/grpclog"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const serviceName = "storage.googleapis.com"
|
||||
|
||||
// For more information on implementing a client constructor hook, see
|
||||
// https://github.com/googleapis/google-cloud-go/wiki/Customizing-constructors.
|
||||
type clientHookParams struct{}
|
||||
type clientHook func(context.Context, clientHookParams) ([]option.ClientOption, error)
|
||||
|
||||
var versionClient string
|
||||
|
||||
func getVersionClient() string {
|
||||
if versionClient == "" {
|
||||
return "UNKNOWN"
|
||||
}
|
||||
return versionClient
|
||||
}
|
||||
|
||||
// DefaultAuthScopes reports the default set of authentication scopes to use with this package.
|
||||
func DefaultAuthScopes() []string {
|
||||
return []string{
|
||||
"https://www.googleapis.com/auth/cloud-platform",
|
||||
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||
"https://www.googleapis.com/auth/devstorage.read_write",
|
||||
}
|
||||
}
|
||||
|
||||
func executeRPC[I proto.Message, O proto.Message](ctx context.Context, fn func(context.Context, I, ...grpc.CallOption) (O, error), req I, opts []grpc.CallOption, logger *slog.Logger, rpc string) (O, error) {
|
||||
var zero O
|
||||
logger.DebugContext(ctx, "api request", "serviceName", serviceName, "rpcName", rpc, "request", grpclog.ProtoMessageRequest(ctx, req))
|
||||
resp, err := fn(ctx, req, opts...)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
logger.DebugContext(ctx, "api response", "serviceName", serviceName, "rpcName", rpc, "response", grpclog.ProtoMessageResponse(resp))
|
||||
return resp, err
|
||||
}
|
||||
+169
-545
@@ -1,4 +1,4 @@
|
||||
// Copyright 2024 Google LLC
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -19,6 +19,7 @@ package storage
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math"
|
||||
"net/url"
|
||||
"regexp"
|
||||
@@ -56,6 +57,7 @@ type CallOptions struct {
|
||||
CancelResumableWrite []gax.CallOption
|
||||
GetObject []gax.CallOption
|
||||
ReadObject []gax.CallOption
|
||||
BidiReadObject []gax.CallOption
|
||||
UpdateObject []gax.CallOption
|
||||
WriteObject []gax.CallOption
|
||||
BidiWriteObject []gax.CallOption
|
||||
@@ -63,16 +65,7 @@ type CallOptions struct {
|
||||
RewriteObject []gax.CallOption
|
||||
StartResumableWrite []gax.CallOption
|
||||
QueryWriteStatus []gax.CallOption
|
||||
GetServiceAccount []gax.CallOption
|
||||
CreateHmacKey []gax.CallOption
|
||||
DeleteHmacKey []gax.CallOption
|
||||
GetHmacKey []gax.CallOption
|
||||
ListHmacKeys []gax.CallOption
|
||||
UpdateHmacKey []gax.CallOption
|
||||
DeleteNotificationConfig []gax.CallOption
|
||||
GetNotificationConfig []gax.CallOption
|
||||
CreateNotificationConfig []gax.CallOption
|
||||
ListNotificationConfigs []gax.CallOption
|
||||
MoveObject []gax.CallOption
|
||||
}
|
||||
|
||||
func defaultGRPCClientOptions() []option.ClientOption {
|
||||
@@ -286,6 +279,18 @@ func defaultCallOptions() *CallOptions {
|
||||
})
|
||||
}),
|
||||
},
|
||||
BidiReadObject: []gax.CallOption{
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
UpdateObject: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
@@ -375,124 +380,7 @@ func defaultCallOptions() *CallOptions {
|
||||
})
|
||||
}),
|
||||
},
|
||||
GetServiceAccount: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
CreateHmacKey: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
DeleteHmacKey: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
GetHmacKey: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
ListHmacKeys: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
UpdateHmacKey: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
DeleteNotificationConfig: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
GetNotificationConfig: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
CreateNotificationConfig: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
codes.DeadlineExceeded,
|
||||
codes.Unavailable,
|
||||
}, gax.Backoff{
|
||||
Initial: 1000 * time.Millisecond,
|
||||
Max: 60000 * time.Millisecond,
|
||||
Multiplier: 2.00,
|
||||
})
|
||||
}),
|
||||
},
|
||||
ListNotificationConfigs: []gax.CallOption{
|
||||
MoveObject: []gax.CallOption{
|
||||
gax.WithTimeout(60000 * time.Millisecond),
|
||||
gax.WithRetry(func() gax.Retryer {
|
||||
return gax.OnCodes([]codes.Code{
|
||||
@@ -528,6 +416,7 @@ type internalClient interface {
|
||||
CancelResumableWrite(context.Context, *storagepb.CancelResumableWriteRequest, ...gax.CallOption) (*storagepb.CancelResumableWriteResponse, error)
|
||||
GetObject(context.Context, *storagepb.GetObjectRequest, ...gax.CallOption) (*storagepb.Object, error)
|
||||
ReadObject(context.Context, *storagepb.ReadObjectRequest, ...gax.CallOption) (storagepb.Storage_ReadObjectClient, error)
|
||||
BidiReadObject(context.Context, ...gax.CallOption) (storagepb.Storage_BidiReadObjectClient, error)
|
||||
UpdateObject(context.Context, *storagepb.UpdateObjectRequest, ...gax.CallOption) (*storagepb.Object, error)
|
||||
WriteObject(context.Context, ...gax.CallOption) (storagepb.Storage_WriteObjectClient, error)
|
||||
BidiWriteObject(context.Context, ...gax.CallOption) (storagepb.Storage_BidiWriteObjectClient, error)
|
||||
@@ -535,16 +424,7 @@ type internalClient interface {
|
||||
RewriteObject(context.Context, *storagepb.RewriteObjectRequest, ...gax.CallOption) (*storagepb.RewriteResponse, error)
|
||||
StartResumableWrite(context.Context, *storagepb.StartResumableWriteRequest, ...gax.CallOption) (*storagepb.StartResumableWriteResponse, error)
|
||||
QueryWriteStatus(context.Context, *storagepb.QueryWriteStatusRequest, ...gax.CallOption) (*storagepb.QueryWriteStatusResponse, error)
|
||||
GetServiceAccount(context.Context, *storagepb.GetServiceAccountRequest, ...gax.CallOption) (*storagepb.ServiceAccount, error)
|
||||
CreateHmacKey(context.Context, *storagepb.CreateHmacKeyRequest, ...gax.CallOption) (*storagepb.CreateHmacKeyResponse, error)
|
||||
DeleteHmacKey(context.Context, *storagepb.DeleteHmacKeyRequest, ...gax.CallOption) error
|
||||
GetHmacKey(context.Context, *storagepb.GetHmacKeyRequest, ...gax.CallOption) (*storagepb.HmacKeyMetadata, error)
|
||||
ListHmacKeys(context.Context, *storagepb.ListHmacKeysRequest, ...gax.CallOption) *HmacKeyMetadataIterator
|
||||
UpdateHmacKey(context.Context, *storagepb.UpdateHmacKeyRequest, ...gax.CallOption) (*storagepb.HmacKeyMetadata, error)
|
||||
DeleteNotificationConfig(context.Context, *storagepb.DeleteNotificationConfigRequest, ...gax.CallOption) error
|
||||
GetNotificationConfig(context.Context, *storagepb.GetNotificationConfigRequest, ...gax.CallOption) (*storagepb.NotificationConfig, error)
|
||||
CreateNotificationConfig(context.Context, *storagepb.CreateNotificationConfigRequest, ...gax.CallOption) (*storagepb.NotificationConfig, error)
|
||||
ListNotificationConfigs(context.Context, *storagepb.ListNotificationConfigsRequest, ...gax.CallOption) *NotificationConfigIterator
|
||||
MoveObject(context.Context, *storagepb.MoveObjectRequest, ...gax.CallOption) (*storagepb.Object, error)
|
||||
}
|
||||
|
||||
// Client is a client for interacting with Cloud Storage API.
|
||||
@@ -664,12 +544,26 @@ func (c *Client) ComposeObject(ctx context.Context, req *storagepb.ComposeObject
|
||||
return c.internalClient.ComposeObject(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// DeleteObject deletes an object and its metadata.
|
||||
// DeleteObject deletes an object and its metadata. Deletions are permanent if versioning
|
||||
// is not enabled for the bucket, or if the generation parameter is used, or
|
||||
// if soft delete (at https://cloud.google.com/storage/docs/soft-delete) is not
|
||||
// enabled for the bucket.
|
||||
// When this API is used to delete an object from a bucket that has soft
|
||||
// delete policy enabled, the object becomes soft deleted, and the
|
||||
// softDeleteTime and hardDeleteTime properties are set on the object.
|
||||
// This API cannot be used to permanently delete soft-deleted objects.
|
||||
// Soft-deleted objects are permanently deleted according to their
|
||||
// hardDeleteTime.
|
||||
//
|
||||
// Deletions are normally permanent when versioning is disabled or whenever
|
||||
// the generation parameter is used. However, if soft delete is enabled for
|
||||
// the bucket, deleted objects can be restored using RestoreObject until the
|
||||
// soft delete retention period has passed.
|
||||
// You can use the [RestoreObject][google.storage.v2.Storage.RestoreObject]
|
||||
// API to restore soft-deleted objects until the soft delete retention period
|
||||
// has passed.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// Requires storage.objects.delete
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions) on
|
||||
// the bucket.
|
||||
func (c *Client) DeleteObject(ctx context.Context, req *storagepb.DeleteObjectRequest, opts ...gax.CallOption) error {
|
||||
return c.internalClient.DeleteObject(ctx, req, opts...)
|
||||
}
|
||||
@@ -691,16 +585,52 @@ func (c *Client) CancelResumableWrite(ctx context.Context, req *storagepb.Cancel
|
||||
return c.internalClient.CancelResumableWrite(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// GetObject retrieves an object’s metadata.
|
||||
// GetObject retrieves object metadata.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// Requires storage.objects.get
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions) on
|
||||
// the bucket. To return object ACLs, the authenticated user must also have
|
||||
// the storage.objects.getIamPolicy permission.
|
||||
func (c *Client) GetObject(ctx context.Context, req *storagepb.GetObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) {
|
||||
return c.internalClient.GetObject(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// ReadObject reads an object’s data.
|
||||
// ReadObject retrieves object data.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// Requires storage.objects.get
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions) on
|
||||
// the bucket.
|
||||
func (c *Client) ReadObject(ctx context.Context, req *storagepb.ReadObjectRequest, opts ...gax.CallOption) (storagepb.Storage_ReadObjectClient, error) {
|
||||
return c.internalClient.ReadObject(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// BidiReadObject reads an object’s data.
|
||||
//
|
||||
// This is a bi-directional API with the added support for reading multiple
|
||||
// ranges within one stream both within and across multiple messages.
|
||||
// If the server encountered an error for any of the inputs, the stream will
|
||||
// be closed with the relevant error code.
|
||||
// Because the API allows for multiple outstanding requests, when the stream
|
||||
// is closed the error response will contain a BidiReadObjectRangesError proto
|
||||
// in the error extension describing the error for each outstanding read_id.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// # Requires storage.objects.get
|
||||
//
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions) on
|
||||
// the bucket.
|
||||
//
|
||||
// This API is currently in preview and is not yet available for general
|
||||
// use.
|
||||
func (c *Client) BidiReadObject(ctx context.Context, opts ...gax.CallOption) (storagepb.Storage_BidiReadObjectClient, error) {
|
||||
return c.internalClient.BidiReadObject(ctx, opts...)
|
||||
}
|
||||
|
||||
// UpdateObject updates an object’s metadata.
|
||||
// Equivalent to JSON API’s storage.objects.patch.
|
||||
func (c *Client) UpdateObject(ctx context.Context, req *storagepb.UpdateObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) {
|
||||
@@ -770,6 +700,12 @@ func (c *Client) UpdateObject(ctx context.Context, req *storagepb.UpdateObjectRe
|
||||
// Alternatively, the BidiWriteObject operation may be used to write an
|
||||
// object with controls over flushing and the ability to fetch the ability to
|
||||
// determine the current persisted size.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// Requires storage.objects.create
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions) on
|
||||
// the bucket.
|
||||
func (c *Client) WriteObject(ctx context.Context, opts ...gax.CallOption) (storagepb.Storage_WriteObjectClient, error) {
|
||||
return c.internalClient.WriteObject(ctx, opts...)
|
||||
}
|
||||
@@ -794,6 +730,13 @@ func (c *Client) BidiWriteObject(ctx context.Context, opts ...gax.CallOption) (s
|
||||
}
|
||||
|
||||
// ListObjects retrieves a list of objects matching the criteria.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// The authenticated user requires storage.objects.list
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions)
|
||||
// to use this method. To return object ACLs, the authenticated user must also
|
||||
// have the storage.objects.getIamPolicy permission.
|
||||
func (c *Client) ListObjects(ctx context.Context, req *storagepb.ListObjectsRequest, opts ...gax.CallOption) *ObjectIterator {
|
||||
return c.internalClient.ListObjects(ctx, req, opts...)
|
||||
}
|
||||
@@ -804,101 +747,47 @@ func (c *Client) RewriteObject(ctx context.Context, req *storagepb.RewriteObject
|
||||
return c.internalClient.RewriteObject(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// StartResumableWrite starts a resumable write. How long the write operation remains valid, and
|
||||
// what happens when the write operation becomes invalid, are
|
||||
// service-dependent.
|
||||
// StartResumableWrite starts a resumable write operation. This
|
||||
// method is part of the Resumable
|
||||
// upload (at https://cloud.google.com/storage/docs/resumable-uploads) feature.
|
||||
// This allows you to upload large objects in multiple chunks, which is more
|
||||
// resilient to network interruptions than a single upload. The validity
|
||||
// duration of the write operation, and the consequences of it becoming
|
||||
// invalid, are service-dependent.
|
||||
//
|
||||
// IAM Permissions:
|
||||
//
|
||||
// Requires storage.objects.create
|
||||
// IAM permission (at https://cloud.google.com/iam/docs/overview#permissions) on
|
||||
// the bucket.
|
||||
func (c *Client) StartResumableWrite(ctx context.Context, req *storagepb.StartResumableWriteRequest, opts ...gax.CallOption) (*storagepb.StartResumableWriteResponse, error) {
|
||||
return c.internalClient.StartResumableWrite(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// QueryWriteStatus determines the persisted_size for an object that is being written, which
|
||||
// can then be used as the write_offset for the next Write() call.
|
||||
// QueryWriteStatus determines the persisted_size of an object that is being written. This
|
||||
// method is part of the resumable
|
||||
// upload (at https://cloud.google.com/storage/docs/resumable-uploads) feature.
|
||||
// The returned value is the size of the object that has been persisted so
|
||||
// far. The value can be used as the write_offset for the next Write()
|
||||
// call.
|
||||
//
|
||||
// If the object does not exist (i.e., the object has been deleted, or the
|
||||
// first Write() has not yet reached the service), this method returns the
|
||||
// If the object does not exist, meaning if it was deleted, or the
|
||||
// first Write() has not yet reached the service, this method returns the
|
||||
// error NOT_FOUND.
|
||||
//
|
||||
// The client may call QueryWriteStatus() at any time to determine how
|
||||
// much data has been processed for this object. This is useful if the
|
||||
// client is buffering data and needs to know which data can be safely
|
||||
// evicted. For any sequence of QueryWriteStatus() calls for a given
|
||||
// object name, the sequence of returned persisted_size values will be
|
||||
// This method is useful for clients that buffer data and need to know which
|
||||
// data can be safely evicted. The client can call QueryWriteStatus() at any
|
||||
// time to determine how much data has been logged for this object.
|
||||
// For any sequence of QueryWriteStatus() calls for a given
|
||||
// object name, the sequence of returned persisted_size values are
|
||||
// non-decreasing.
|
||||
func (c *Client) QueryWriteStatus(ctx context.Context, req *storagepb.QueryWriteStatusRequest, opts ...gax.CallOption) (*storagepb.QueryWriteStatusResponse, error) {
|
||||
return c.internalClient.QueryWriteStatus(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// GetServiceAccount retrieves the name of a project’s Google Cloud Storage service account.
|
||||
//
|
||||
// Deprecated: GetServiceAccount may be removed in a future version.
|
||||
func (c *Client) GetServiceAccount(ctx context.Context, req *storagepb.GetServiceAccountRequest, opts ...gax.CallOption) (*storagepb.ServiceAccount, error) {
|
||||
return c.internalClient.GetServiceAccount(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// CreateHmacKey creates a new HMAC key for the given service account.
|
||||
//
|
||||
// Deprecated: CreateHmacKey may be removed in a future version.
|
||||
func (c *Client) CreateHmacKey(ctx context.Context, req *storagepb.CreateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.CreateHmacKeyResponse, error) {
|
||||
return c.internalClient.CreateHmacKey(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// DeleteHmacKey deletes a given HMAC key. Key must be in an INACTIVE state.
|
||||
//
|
||||
// Deprecated: DeleteHmacKey may be removed in a future version.
|
||||
func (c *Client) DeleteHmacKey(ctx context.Context, req *storagepb.DeleteHmacKeyRequest, opts ...gax.CallOption) error {
|
||||
return c.internalClient.DeleteHmacKey(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// GetHmacKey gets an existing HMAC key metadata for the given id.
|
||||
//
|
||||
// Deprecated: GetHmacKey may be removed in a future version.
|
||||
func (c *Client) GetHmacKey(ctx context.Context, req *storagepb.GetHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) {
|
||||
return c.internalClient.GetHmacKey(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// ListHmacKeys lists HMAC keys under a given project with the additional filters provided.
|
||||
//
|
||||
// Deprecated: ListHmacKeys may be removed in a future version.
|
||||
func (c *Client) ListHmacKeys(ctx context.Context, req *storagepb.ListHmacKeysRequest, opts ...gax.CallOption) *HmacKeyMetadataIterator {
|
||||
return c.internalClient.ListHmacKeys(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// UpdateHmacKey updates a given HMAC key state between ACTIVE and INACTIVE.
|
||||
//
|
||||
// Deprecated: UpdateHmacKey may be removed in a future version.
|
||||
func (c *Client) UpdateHmacKey(ctx context.Context, req *storagepb.UpdateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) {
|
||||
return c.internalClient.UpdateHmacKey(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// DeleteNotificationConfig permanently deletes a NotificationConfig.
|
||||
//
|
||||
// Deprecated: DeleteNotificationConfig may be removed in a future version.
|
||||
func (c *Client) DeleteNotificationConfig(ctx context.Context, req *storagepb.DeleteNotificationConfigRequest, opts ...gax.CallOption) error {
|
||||
return c.internalClient.DeleteNotificationConfig(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// GetNotificationConfig view a NotificationConfig.
|
||||
//
|
||||
// Deprecated: GetNotificationConfig may be removed in a future version.
|
||||
func (c *Client) GetNotificationConfig(ctx context.Context, req *storagepb.GetNotificationConfigRequest, opts ...gax.CallOption) (*storagepb.NotificationConfig, error) {
|
||||
return c.internalClient.GetNotificationConfig(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// CreateNotificationConfig creates a NotificationConfig for a given bucket.
|
||||
// These NotificationConfigs, when triggered, publish messages to the
|
||||
// specified Pub/Sub topics. See
|
||||
// https://cloud.google.com/storage/docs/pubsub-notifications (at https://cloud.google.com/storage/docs/pubsub-notifications).
|
||||
//
|
||||
// Deprecated: CreateNotificationConfig may be removed in a future version.
|
||||
func (c *Client) CreateNotificationConfig(ctx context.Context, req *storagepb.CreateNotificationConfigRequest, opts ...gax.CallOption) (*storagepb.NotificationConfig, error) {
|
||||
return c.internalClient.CreateNotificationConfig(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// ListNotificationConfigs retrieves a list of NotificationConfigs for a given bucket.
|
||||
//
|
||||
// Deprecated: ListNotificationConfigs may be removed in a future version.
|
||||
func (c *Client) ListNotificationConfigs(ctx context.Context, req *storagepb.ListNotificationConfigsRequest, opts ...gax.CallOption) *NotificationConfigIterator {
|
||||
return c.internalClient.ListNotificationConfigs(ctx, req, opts...)
|
||||
// MoveObject moves the source object to the destination object in the same bucket.
|
||||
func (c *Client) MoveObject(ctx context.Context, req *storagepb.MoveObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) {
|
||||
return c.internalClient.MoveObject(ctx, req, opts...)
|
||||
}
|
||||
|
||||
// gRPCClient is a client for interacting with Cloud Storage API over gRPC transport.
|
||||
@@ -916,6 +805,8 @@ type gRPCClient struct {
|
||||
|
||||
// The x-goog-* metadata to be sent with each request.
|
||||
xGoogHeaders []string
|
||||
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// NewClient creates a new storage client based on gRPC.
|
||||
@@ -963,6 +854,7 @@ func NewClient(ctx context.Context, opts ...option.ClientOption) (*Client, error
|
||||
connPool: connPool,
|
||||
client: storagepb.NewStorageClient(connPool),
|
||||
CallOptions: &client.CallOptions,
|
||||
logger: internaloption.GetLogger(opts),
|
||||
}
|
||||
c.setGoogleClientInfo()
|
||||
|
||||
@@ -1013,7 +905,7 @@ func (c *gRPCClient) DeleteBucket(ctx context.Context, req *storagepb.DeleteBuck
|
||||
opts = append((*c.CallOptions).DeleteBucket[0:len((*c.CallOptions).DeleteBucket):len((*c.CallOptions).DeleteBucket)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
_, err = c.client.DeleteBucket(ctx, req, settings.GRPC...)
|
||||
_, err = executeRPC(ctx, c.client.DeleteBucket, req, settings.GRPC, c.logger, "DeleteBucket")
|
||||
return err
|
||||
}, opts...)
|
||||
return err
|
||||
@@ -1037,7 +929,7 @@ func (c *gRPCClient) GetBucket(ctx context.Context, req *storagepb.GetBucketRequ
|
||||
var resp *storagepb.Bucket
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.GetBucket(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.GetBucket, req, settings.GRPC, c.logger, "GetBucket")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1067,7 +959,7 @@ func (c *gRPCClient) CreateBucket(ctx context.Context, req *storagepb.CreateBuck
|
||||
var resp *storagepb.Bucket
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.CreateBucket(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.CreateBucket, req, settings.GRPC, c.logger, "CreateBucket")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1105,7 +997,7 @@ func (c *gRPCClient) ListBuckets(ctx context.Context, req *storagepb.ListBuckets
|
||||
}
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.ListBuckets(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.ListBuckets, req, settings.GRPC, c.logger, "ListBuckets")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1149,7 +1041,7 @@ func (c *gRPCClient) LockBucketRetentionPolicy(ctx context.Context, req *storage
|
||||
var resp *storagepb.Bucket
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.LockBucketRetentionPolicy(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.LockBucketRetentionPolicy, req, settings.GRPC, c.logger, "LockBucketRetentionPolicy")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1176,7 +1068,7 @@ func (c *gRPCClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRe
|
||||
var resp *iampb.Policy
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.GetIamPolicy(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.GetIamPolicy, req, settings.GRPC, c.logger, "GetIamPolicy")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1203,7 +1095,7 @@ func (c *gRPCClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRe
|
||||
var resp *iampb.Policy
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.SetIamPolicy(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.SetIamPolicy, req, settings.GRPC, c.logger, "SetIamPolicy")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1236,7 +1128,7 @@ func (c *gRPCClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamP
|
||||
var resp *iampb.TestIamPermissionsResponse
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.TestIamPermissions(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.TestIamPermissions, req, settings.GRPC, c.logger, "TestIamPermissions")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1263,7 +1155,7 @@ func (c *gRPCClient) UpdateBucket(ctx context.Context, req *storagepb.UpdateBuck
|
||||
var resp *storagepb.Bucket
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.UpdateBucket(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.UpdateBucket, req, settings.GRPC, c.logger, "UpdateBucket")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1290,7 +1182,7 @@ func (c *gRPCClient) ComposeObject(ctx context.Context, req *storagepb.ComposeOb
|
||||
var resp *storagepb.Object
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.ComposeObject(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.ComposeObject, req, settings.GRPC, c.logger, "ComposeObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1316,7 +1208,7 @@ func (c *gRPCClient) DeleteObject(ctx context.Context, req *storagepb.DeleteObje
|
||||
opts = append((*c.CallOptions).DeleteObject[0:len((*c.CallOptions).DeleteObject):len((*c.CallOptions).DeleteObject)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
_, err = c.client.DeleteObject(ctx, req, settings.GRPC...)
|
||||
_, err = executeRPC(ctx, c.client.DeleteObject, req, settings.GRPC, c.logger, "DeleteObject")
|
||||
return err
|
||||
}, opts...)
|
||||
return err
|
||||
@@ -1340,7 +1232,7 @@ func (c *gRPCClient) RestoreObject(ctx context.Context, req *storagepb.RestoreOb
|
||||
var resp *storagepb.Object
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.RestoreObject(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.RestoreObject, req, settings.GRPC, c.logger, "RestoreObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1367,7 +1259,7 @@ func (c *gRPCClient) CancelResumableWrite(ctx context.Context, req *storagepb.Ca
|
||||
var resp *storagepb.CancelResumableWriteResponse
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.CancelResumableWrite(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.CancelResumableWrite, req, settings.GRPC, c.logger, "CancelResumableWrite")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1394,7 +1286,7 @@ func (c *gRPCClient) GetObject(ctx context.Context, req *storagepb.GetObjectRequ
|
||||
var resp *storagepb.Object
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.GetObject(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.GetObject, req, settings.GRPC, c.logger, "GetObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1421,7 +1313,26 @@ func (c *gRPCClient) ReadObject(ctx context.Context, req *storagepb.ReadObjectRe
|
||||
var resp storagepb.Storage_ReadObjectClient
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
c.logger.DebugContext(ctx, "api streaming client request", "serviceName", serviceName, "rpcName", "ReadObject")
|
||||
resp, err = c.client.ReadObject(ctx, req, settings.GRPC...)
|
||||
c.logger.DebugContext(ctx, "api streaming client response", "serviceName", serviceName, "rpcName", "ReadObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) BidiReadObject(ctx context.Context, opts ...gax.CallOption) (storagepb.Storage_BidiReadObjectClient, error) {
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, c.xGoogHeaders...)
|
||||
var resp storagepb.Storage_BidiReadObjectClient
|
||||
opts = append((*c.CallOptions).BidiReadObject[0:len((*c.CallOptions).BidiReadObject):len((*c.CallOptions).BidiReadObject)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
c.logger.DebugContext(ctx, "api streaming client request", "serviceName", serviceName, "rpcName", "BidiReadObject")
|
||||
resp, err = c.client.BidiReadObject(ctx, settings.GRPC...)
|
||||
c.logger.DebugContext(ctx, "api streaming client response", "serviceName", serviceName, "rpcName", "BidiReadObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1448,7 +1359,7 @@ func (c *gRPCClient) UpdateObject(ctx context.Context, req *storagepb.UpdateObje
|
||||
var resp *storagepb.Object
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.UpdateObject(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.UpdateObject, req, settings.GRPC, c.logger, "UpdateObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1463,7 +1374,9 @@ func (c *gRPCClient) WriteObject(ctx context.Context, opts ...gax.CallOption) (s
|
||||
opts = append((*c.CallOptions).WriteObject[0:len((*c.CallOptions).WriteObject):len((*c.CallOptions).WriteObject)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
c.logger.DebugContext(ctx, "api streaming client request", "serviceName", serviceName, "rpcName", "WriteObject")
|
||||
resp, err = c.client.WriteObject(ctx, settings.GRPC...)
|
||||
c.logger.DebugContext(ctx, "api streaming client response", "serviceName", serviceName, "rpcName", "WriteObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1478,7 +1391,9 @@ func (c *gRPCClient) BidiWriteObject(ctx context.Context, opts ...gax.CallOption
|
||||
opts = append((*c.CallOptions).BidiWriteObject[0:len((*c.CallOptions).BidiWriteObject):len((*c.CallOptions).BidiWriteObject)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
c.logger.DebugContext(ctx, "api streaming client request", "serviceName", serviceName, "rpcName", "BidiWriteObject")
|
||||
resp, err = c.client.BidiWriteObject(ctx, settings.GRPC...)
|
||||
c.logger.DebugContext(ctx, "api streaming client response", "serviceName", serviceName, "rpcName", "BidiWriteObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1516,7 +1431,7 @@ func (c *gRPCClient) ListObjects(ctx context.Context, req *storagepb.ListObjects
|
||||
}
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.ListObjects(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.ListObjects, req, settings.GRPC, c.logger, "ListObjects")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1563,7 +1478,7 @@ func (c *gRPCClient) RewriteObject(ctx context.Context, req *storagepb.RewriteOb
|
||||
var resp *storagepb.RewriteResponse
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.RewriteObject(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.RewriteObject, req, settings.GRPC, c.logger, "RewriteObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1590,7 +1505,7 @@ func (c *gRPCClient) StartResumableWrite(ctx context.Context, req *storagepb.Sta
|
||||
var resp *storagepb.StartResumableWriteResponse
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.StartResumableWrite(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.StartResumableWrite, req, settings.GRPC, c.logger, "StartResumableWrite")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1617,7 +1532,7 @@ func (c *gRPCClient) QueryWriteStatus(ctx context.Context, req *storagepb.QueryW
|
||||
var resp *storagepb.QueryWriteStatusResponse
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.QueryWriteStatus(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.QueryWriteStatus, req, settings.GRPC, c.logger, "QueryWriteStatus")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1626,11 +1541,11 @@ func (c *gRPCClient) QueryWriteStatus(ctx context.Context, req *storagepb.QueryW
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) GetServiceAccount(ctx context.Context, req *storagepb.GetServiceAccountRequest, opts ...gax.CallOption) (*storagepb.ServiceAccount, error) {
|
||||
func (c *gRPCClient) MoveObject(ctx context.Context, req *storagepb.MoveObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 {
|
||||
routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])
|
||||
if reg := regexp.MustCompile("(?P<bucket>.*)"); reg.MatchString(req.GetBucket()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1])) > 0 {
|
||||
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetBucket())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
@@ -1640,11 +1555,11 @@ func (c *gRPCClient) GetServiceAccount(ctx context.Context, req *storagepb.GetSe
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).GetServiceAccount[0:len((*c.CallOptions).GetServiceAccount):len((*c.CallOptions).GetServiceAccount)], opts...)
|
||||
var resp *storagepb.ServiceAccount
|
||||
opts = append((*c.CallOptions).MoveObject[0:len((*c.CallOptions).MoveObject):len((*c.CallOptions).MoveObject)], opts...)
|
||||
var resp *storagepb.Object
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.GetServiceAccount(ctx, req, settings.GRPC...)
|
||||
resp, err = executeRPC(ctx, c.client.MoveObject, req, settings.GRPC, c.logger, "MoveObject")
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
@@ -1652,294 +1567,3 @@ func (c *gRPCClient) GetServiceAccount(ctx context.Context, req *storagepb.GetSe
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) CreateHmacKey(ctx context.Context, req *storagepb.CreateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.CreateHmacKeyResponse, error) {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 {
|
||||
routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).CreateHmacKey[0:len((*c.CallOptions).CreateHmacKey):len((*c.CallOptions).CreateHmacKey)], opts...)
|
||||
var resp *storagepb.CreateHmacKeyResponse
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.CreateHmacKey(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) DeleteHmacKey(ctx context.Context, req *storagepb.DeleteHmacKeyRequest, opts ...gax.CallOption) error {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 {
|
||||
routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).DeleteHmacKey[0:len((*c.CallOptions).DeleteHmacKey):len((*c.CallOptions).DeleteHmacKey)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
_, err = c.client.DeleteHmacKey(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *gRPCClient) GetHmacKey(ctx context.Context, req *storagepb.GetHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 {
|
||||
routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).GetHmacKey[0:len((*c.CallOptions).GetHmacKey):len((*c.CallOptions).GetHmacKey)], opts...)
|
||||
var resp *storagepb.HmacKeyMetadata
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.GetHmacKey(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) ListHmacKeys(ctx context.Context, req *storagepb.ListHmacKeysRequest, opts ...gax.CallOption) *HmacKeyMetadataIterator {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(.*)"); reg.MatchString(req.GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])) > 0 {
|
||||
routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetProject())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).ListHmacKeys[0:len((*c.CallOptions).ListHmacKeys):len((*c.CallOptions).ListHmacKeys)], opts...)
|
||||
it := &HmacKeyMetadataIterator{}
|
||||
req = proto.Clone(req).(*storagepb.ListHmacKeysRequest)
|
||||
it.InternalFetch = func(pageSize int, pageToken string) ([]*storagepb.HmacKeyMetadata, string, error) {
|
||||
resp := &storagepb.ListHmacKeysResponse{}
|
||||
if pageToken != "" {
|
||||
req.PageToken = pageToken
|
||||
}
|
||||
if pageSize > math.MaxInt32 {
|
||||
req.PageSize = math.MaxInt32
|
||||
} else if pageSize != 0 {
|
||||
req.PageSize = int32(pageSize)
|
||||
}
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.ListHmacKeys(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
it.Response = resp
|
||||
return resp.GetHmacKeys(), resp.GetNextPageToken(), nil
|
||||
}
|
||||
fetch := func(pageSize int, pageToken string) (string, error) {
|
||||
items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
it.items = append(it.items, items...)
|
||||
return nextPageToken, nil
|
||||
}
|
||||
|
||||
it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
|
||||
it.pageInfo.MaxSize = int(req.GetPageSize())
|
||||
it.pageInfo.Token = req.GetPageToken()
|
||||
|
||||
return it
|
||||
}
|
||||
|
||||
func (c *gRPCClient) UpdateHmacKey(ctx context.Context, req *storagepb.UpdateHmacKeyRequest, opts ...gax.CallOption) (*storagepb.HmacKeyMetadata, error) {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(?P<project>.*)"); reg.MatchString(req.GetHmacKey().GetProject()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetHmacKey().GetProject())[1])) > 0 {
|
||||
routingHeadersMap["project"] = url.QueryEscape(reg.FindStringSubmatch(req.GetHmacKey().GetProject())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).UpdateHmacKey[0:len((*c.CallOptions).UpdateHmacKey):len((*c.CallOptions).UpdateHmacKey)], opts...)
|
||||
var resp *storagepb.HmacKeyMetadata
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.UpdateHmacKey(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) DeleteNotificationConfig(ctx context.Context, req *storagepb.DeleteNotificationConfigRequest, opts ...gax.CallOption) error {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(?P<bucket>projects/[^/]+/buckets/[^/]+)(?:/.*)?"); reg.MatchString(req.GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])) > 0 {
|
||||
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).DeleteNotificationConfig[0:len((*c.CallOptions).DeleteNotificationConfig):len((*c.CallOptions).DeleteNotificationConfig)], opts...)
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
_, err = c.client.DeleteNotificationConfig(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *gRPCClient) GetNotificationConfig(ctx context.Context, req *storagepb.GetNotificationConfigRequest, opts ...gax.CallOption) (*storagepb.NotificationConfig, error) {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(?P<bucket>projects/[^/]+/buckets/[^/]+)(?:/.*)?"); reg.MatchString(req.GetName()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])) > 0 {
|
||||
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetName())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).GetNotificationConfig[0:len((*c.CallOptions).GetNotificationConfig):len((*c.CallOptions).GetNotificationConfig)], opts...)
|
||||
var resp *storagepb.NotificationConfig
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.GetNotificationConfig(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) CreateNotificationConfig(ctx context.Context, req *storagepb.CreateNotificationConfigRequest, opts ...gax.CallOption) (*storagepb.NotificationConfig, error) {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(?P<bucket>.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 {
|
||||
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).CreateNotificationConfig[0:len((*c.CallOptions).CreateNotificationConfig):len((*c.CallOptions).CreateNotificationConfig)], opts...)
|
||||
var resp *storagepb.NotificationConfig
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.CreateNotificationConfig(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *gRPCClient) ListNotificationConfigs(ctx context.Context, req *storagepb.ListNotificationConfigsRequest, opts ...gax.CallOption) *NotificationConfigIterator {
|
||||
routingHeaders := ""
|
||||
routingHeadersMap := make(map[string]string)
|
||||
if reg := regexp.MustCompile("(?P<bucket>.*)"); reg.MatchString(req.GetParent()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])) > 0 {
|
||||
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetParent())[1])
|
||||
}
|
||||
for headerName, headerValue := range routingHeadersMap {
|
||||
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
|
||||
}
|
||||
routingHeaders = strings.TrimSuffix(routingHeaders, "&")
|
||||
hds := []string{"x-goog-request-params", routingHeaders}
|
||||
|
||||
hds = append(c.xGoogHeaders, hds...)
|
||||
ctx = gax.InsertMetadataIntoOutgoingContext(ctx, hds...)
|
||||
opts = append((*c.CallOptions).ListNotificationConfigs[0:len((*c.CallOptions).ListNotificationConfigs):len((*c.CallOptions).ListNotificationConfigs)], opts...)
|
||||
it := &NotificationConfigIterator{}
|
||||
req = proto.Clone(req).(*storagepb.ListNotificationConfigsRequest)
|
||||
it.InternalFetch = func(pageSize int, pageToken string) ([]*storagepb.NotificationConfig, string, error) {
|
||||
resp := &storagepb.ListNotificationConfigsResponse{}
|
||||
if pageToken != "" {
|
||||
req.PageToken = pageToken
|
||||
}
|
||||
if pageSize > math.MaxInt32 {
|
||||
req.PageSize = math.MaxInt32
|
||||
} else if pageSize != 0 {
|
||||
req.PageSize = int32(pageSize)
|
||||
}
|
||||
err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {
|
||||
var err error
|
||||
resp, err = c.client.ListNotificationConfigs(ctx, req, settings.GRPC...)
|
||||
return err
|
||||
}, opts...)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
it.Response = resp
|
||||
return resp.GetNotificationConfigs(), resp.GetNextPageToken(), nil
|
||||
}
|
||||
fetch := func(pageSize int, pageToken string) (string, error) {
|
||||
items, nextPageToken, err := it.InternalFetch(pageSize, pageToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
it.items = append(it.items, items...)
|
||||
return nextPageToken, nil
|
||||
}
|
||||
|
||||
it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf)
|
||||
it.pageInfo.MaxSize = int(req.GetPageSize())
|
||||
it.pageInfo.Token = req.GetPageToken()
|
||||
|
||||
return it
|
||||
}
|
||||
+3730
-4912
File diff suppressed because it is too large.
Load diff
+13
@@ -17,7 +17,20 @@
|
||||
package internal
|
||||
|
||||
var (
|
||||
// WithMetricInterval is a function which is implemented by storage package.
|
||||
// It sets how often to emit metrics when using NewPeriodicReader and must be
|
||||
// greater than 1 minute.
|
||||
WithMetricInterval any // func (*time.Duration) option.ClientOption
|
||||
|
||||
// WithMetricExporter is a function which is implemented by storage package.
|
||||
// Set an alternate client-side metric Exporter to emit metrics through.
|
||||
WithMetricExporter any // func (*metric.Exporter) option.ClientOption
|
||||
|
||||
// WithReadStallTimeout is a function which is implemented by storage package.
|
||||
// It takes ReadStallTimeoutConfig as inputs and returns a option.ClientOption.
|
||||
WithReadStallTimeout any // func (*ReadStallTimeoutConfig) option.ClientOption
|
||||
|
||||
// WithGRPCBidiReads is a function which is implemented by the storage package.
|
||||
// It sets the gRPC client to use the BidiReadObject API for downloads.
|
||||
WithGRPCBidiReads any // func() option.ClientOption
|
||||
)
|
||||
+1
-1
@@ -15,4 +15,4 @@
|
||||
package internal
|
||||
|
||||
// Version is the current tagged release of the library.
|
||||
const Version = "1.45.0"
|
||||
const Version = "1.50.0"
|
||||
+63
-2
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"cloud.google.com/go/storage/experimental"
|
||||
storageinternal "cloud.google.com/go/storage/internal"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/option/internaloption"
|
||||
)
|
||||
@@ -35,8 +36,11 @@ const (
|
||||
)
|
||||
|
||||
func init() {
|
||||
// initialize experimental option.
|
||||
// initialize experimental options
|
||||
storageinternal.WithMetricExporter = withMetricExporter
|
||||
storageinternal.WithMetricInterval = withMetricInterval
|
||||
storageinternal.WithReadStallTimeout = withReadStallTimeout
|
||||
storageinternal.WithGRPCBidiReads = withGRPCBidiReads
|
||||
}
|
||||
|
||||
// getDynamicReadReqIncreaseRateFromEnv returns the value set in the env variable.
|
||||
@@ -69,13 +73,16 @@ func getDynamicReadReqInitialTimeoutSecFromEnv(defaultVal time.Duration) time.Du
|
||||
return val
|
||||
}
|
||||
|
||||
// storageConfig contains the Storage client option configuration that can be
|
||||
// set through storageClientOptions.
|
||||
type storageConfig struct {
|
||||
useJSONforReads bool
|
||||
readAPIWasSet bool
|
||||
disableClientMetrics bool
|
||||
metricExporter *metric.Exporter
|
||||
metricInterval time.Duration
|
||||
manualReader *metric.ManualReader
|
||||
readStallTimeoutConfig *experimental.ReadStallTimeoutConfig
|
||||
grpcBidiReads bool
|
||||
}
|
||||
|
||||
// newStorageConfig generates a new storageConfig with all the given
|
||||
@@ -160,6 +167,48 @@ func (w *withDisabledClientMetrics) ApplyStorageOpt(c *storageConfig) {
|
||||
c.disableClientMetrics = w.disabledClientMetrics
|
||||
}
|
||||
|
||||
type withMeterOptions struct {
|
||||
internaloption.EmbeddableAdapter
|
||||
// set sampling interval
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
func withMetricInterval(interval time.Duration) option.ClientOption {
|
||||
return &withMeterOptions{interval: interval}
|
||||
}
|
||||
|
||||
func (w *withMeterOptions) ApplyStorageOpt(c *storageConfig) {
|
||||
c.metricInterval = w.interval
|
||||
}
|
||||
|
||||
type withMetricExporterConfig struct {
|
||||
internaloption.EmbeddableAdapter
|
||||
// exporter override
|
||||
metricExporter *metric.Exporter
|
||||
}
|
||||
|
||||
func withMetricExporter(ex *metric.Exporter) option.ClientOption {
|
||||
return &withMetricExporterConfig{metricExporter: ex}
|
||||
}
|
||||
|
||||
func (w *withMetricExporterConfig) ApplyStorageOpt(c *storageConfig) {
|
||||
c.metricExporter = w.metricExporter
|
||||
}
|
||||
|
||||
type withTestMetricReaderConfig struct {
|
||||
internaloption.EmbeddableAdapter
|
||||
// reader override
|
||||
metricReader *metric.ManualReader
|
||||
}
|
||||
|
||||
func withTestMetricReader(ex *metric.ManualReader) option.ClientOption {
|
||||
return &withTestMetricReaderConfig{metricReader: ex}
|
||||
}
|
||||
|
||||
func (w *withTestMetricReaderConfig) ApplyStorageOpt(c *storageConfig) {
|
||||
c.manualReader = w.metricReader
|
||||
}
|
||||
|
||||
// WithReadStallTimeout is an option that may be passed to [NewClient].
|
||||
// It enables the client to retry the stalled read request, happens as part of
|
||||
// storage.Reader creation. As the name suggest, timeout is adjusted dynamically
|
||||
@@ -193,3 +242,15 @@ type withReadStallTimeoutConfig struct {
|
||||
func (wrstc *withReadStallTimeoutConfig) ApplyStorageOpt(config *storageConfig) {
|
||||
config.readStallTimeoutConfig = wrstc.readStallTimeoutConfig
|
||||
}
|
||||
|
||||
func withGRPCBidiReads() option.ClientOption {
|
||||
return &withGRPCBidiReadsConfig{}
|
||||
}
|
||||
|
||||
type withGRPCBidiReadsConfig struct {
|
||||
internaloption.EmbeddableAdapter
|
||||
}
|
||||
|
||||
func (w *withGRPCBidiReadsConfig) ApplyStorageOpt(config *storageConfig) {
|
||||
config.grpcBidiReads = true
|
||||
}
|
||||
+142
-1
@@ -22,6 +22,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"cloud.google.com/go/internal/trace"
|
||||
@@ -140,6 +141,7 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
encryptionKey: o.encryptionKey,
|
||||
conds: o.conds,
|
||||
readCompressed: o.readCompressed,
|
||||
handle: &o.readHandle,
|
||||
}
|
||||
|
||||
r, err = o.c.tc.NewRangeReader(ctx, params, opts...)
|
||||
@@ -155,6 +157,49 @@ func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64)
|
||||
return r, err
|
||||
}
|
||||
|
||||
// NewMultiRangeDownloader creates a multi-range reader for an object.
|
||||
// Must be called on a gRPC client created using [NewGRPCClient].
|
||||
//
|
||||
// This uses the gRPC-specific bi-directional read API, which is in private
|
||||
// preview; please contact your account manager if interested.
|
||||
func (o *ObjectHandle) NewMultiRangeDownloader(ctx context.Context) (mrd *MultiRangeDownloader, err error) {
|
||||
// This span covers the life of the reader. It is closed via the context
|
||||
// in Reader.Close.
|
||||
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Object.MultiRangeDownloader")
|
||||
|
||||
if err := o.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if o.conds != nil {
|
||||
if err := o.conds.validate("NewMultiRangeDownloader"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
opts := makeStorageOpts(true, o.retry, o.userProject)
|
||||
|
||||
params := &newMultiRangeDownloaderParams{
|
||||
bucket: o.bucket,
|
||||
conds: o.conds,
|
||||
encryptionKey: o.encryptionKey,
|
||||
gen: o.gen,
|
||||
object: o.object,
|
||||
handle: &o.readHandle,
|
||||
}
|
||||
|
||||
r, err := o.c.tc.NewMultiRangeDownloader(ctx, params, opts...)
|
||||
|
||||
// Pass the context so that the span can be closed in MultiRangeDownloader.Close(), or close the
|
||||
// span now if there is an error.
|
||||
if err == nil {
|
||||
r.ctx = ctx
|
||||
} else {
|
||||
trace.EndSpan(ctx, err)
|
||||
}
|
||||
|
||||
return r, err
|
||||
}
|
||||
|
||||
// decompressiveTranscoding returns true if the request was served decompressed
|
||||
// and different than its original storage form. This happens when the "Content-Encoding"
|
||||
// header is "gzip".
|
||||
@@ -222,12 +267,16 @@ var emptyBody = ioutil.NopCloser(strings.NewReader(""))
|
||||
// the stored CRC, returning an error from Read if there is a mismatch. This integrity check
|
||||
// is skipped if transcoding occurs. See https://cloud.google.com/storage/docs/transcoding.
|
||||
type Reader struct {
|
||||
Attrs ReaderObjectAttrs
|
||||
Attrs ReaderObjectAttrs
|
||||
objectMetadata *map[string]string
|
||||
|
||||
seen, remain, size int64
|
||||
checkCRC bool // Did we check the CRC? This is now only used by tests.
|
||||
|
||||
reader io.ReadCloser
|
||||
ctx context.Context
|
||||
mu sync.Mutex
|
||||
handle *ReadHandle
|
||||
}
|
||||
|
||||
// Close closes the Reader. It must be called when done reading.
|
||||
@@ -298,3 +347,95 @@ func (r *Reader) CacheControl() string {
|
||||
func (r *Reader) LastModified() (time.Time, error) {
|
||||
return r.Attrs.LastModified, nil
|
||||
}
|
||||
|
||||
// Metadata returns user-provided metadata, in key/value pairs.
|
||||
//
|
||||
// It can be nil if no metadata is present, or if the client uses the JSON
|
||||
// API for downloads. Only the XML and gRPC APIs support getting
|
||||
// custom metadata via the Reader; for JSON make a separate call to
|
||||
// ObjectHandle.Attrs.
|
||||
func (r *Reader) Metadata() map[string]string {
|
||||
if r.objectMetadata != nil {
|
||||
return *r.objectMetadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadHandle returns the read handle associated with an object.
|
||||
// ReadHandle will be periodically refreshed.
|
||||
//
|
||||
// ReadHandle requires the gRPC-specific bi-directional read API, which is in
|
||||
// private preview; please contact your account manager if interested.
|
||||
// Note that this only valid for gRPC and only with zonal buckets.
|
||||
func (r *Reader) ReadHandle() ReadHandle {
|
||||
if r.handle == nil {
|
||||
r.handle = &ReadHandle{}
|
||||
}
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
return (*r.handle)
|
||||
}
|
||||
|
||||
// MultiRangeDownloader reads a Cloud Storage object.
|
||||
//
|
||||
// Typically, a MultiRangeDownloader opens a stream to which we can add
|
||||
// different ranges to read from the object.
|
||||
//
|
||||
// This API is currently in preview and is not yet available for general use.
|
||||
type MultiRangeDownloader struct {
|
||||
Attrs ReaderObjectAttrs
|
||||
reader multiRangeDownloader
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
type multiRangeDownloader interface {
|
||||
add(output io.Writer, offset, limit int64, callback func(int64, int64, error))
|
||||
wait()
|
||||
close() error
|
||||
getHandle() []byte
|
||||
}
|
||||
|
||||
// Add adds a new range to MultiRangeDownloader.
|
||||
//
|
||||
// The offset for the first byte to return in the read, relative to the start
|
||||
// of the object.
|
||||
//
|
||||
// A negative offset value will be interpreted as the number of bytes from the
|
||||
// end of the object to be returned. Requesting a negative offset with magnitude
|
||||
// larger than the size of the object will return the entire object. An offset
|
||||
// larger than the size of the object will result in an OutOfRange error.
|
||||
//
|
||||
// A limit of zero indicates that there is no limit, and a negative limit will
|
||||
// cause an error.
|
||||
//
|
||||
// This will initiate the read range but is non-blocking; call callback to
|
||||
// process the result. Add is thread-safe and can be called simultaneously
|
||||
// from different goroutines.
|
||||
func (mrd *MultiRangeDownloader) Add(output io.Writer, offset, length int64, callback func(int64, int64, error)) {
|
||||
mrd.reader.add(output, offset, length, callback)
|
||||
}
|
||||
|
||||
// Close the MultiRangeDownloader. It must be called when done reading.
|
||||
// Adding new ranges after this has been called will cause an error.
|
||||
//
|
||||
// This will immediately close the stream and can result in a
|
||||
// "stream closed early" error if a response for a range is still not processed.
|
||||
// Call [MultiRangeDownloader.Wait] to avoid this error.
|
||||
func (mrd *MultiRangeDownloader) Close() error {
|
||||
err := mrd.reader.close()
|
||||
trace.EndSpan(mrd.ctx, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for all the responses to process on the stream.
|
||||
// Adding new ranges after this has been called will cause an error.
|
||||
// Wait will wait for all callbacks to finish.
|
||||
func (mrd *MultiRangeDownloader) Wait() {
|
||||
mrd.reader.wait()
|
||||
}
|
||||
|
||||
// GetHandle returns the read handle. This can be used to further speed up the
|
||||
// follow up read if the same object is read through a different stream.
|
||||
func (mrd *MultiRangeDownloader) GetHandle() []byte {
|
||||
return mrd.reader.getHandle()
|
||||
}
|
||||
+188
-19
@@ -43,6 +43,9 @@ import (
|
||||
"cloud.google.com/go/storage/internal"
|
||||
"cloud.google.com/go/storage/internal/apiv2/storagepb"
|
||||
"github.com/googleapis/gax-go/v2"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/sdk/metric"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/googleapi"
|
||||
"google.golang.org/api/option"
|
||||
@@ -50,6 +53,8 @@ import (
|
||||
raw "google.golang.org/api/storage/v1"
|
||||
"google.golang.org/api/transport"
|
||||
htransport "google.golang.org/api/transport/http"
|
||||
"google.golang.org/grpc/experimental/stats"
|
||||
"google.golang.org/grpc/stats/opentelemetry"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
@@ -67,8 +72,8 @@ var (
|
||||
// errMethodNotSupported indicates that the method called is not currently supported by the client.
|
||||
// TODO: Export this error when launching the transport-agnostic client.
|
||||
errMethodNotSupported = errors.New("storage: method is not currently supported")
|
||||
// errMethodNotValid indicates that given HTTP method is not valid.
|
||||
errMethodNotValid = fmt.Errorf("storage: HTTP method should be one of %v", reflect.ValueOf(signedURLMethods).MapKeys())
|
||||
// errSignedURLMethodNotValid indicates that given HTTP method is not valid.
|
||||
errSignedURLMethodNotValid = fmt.Errorf("storage: HTTP method should be one of %v", reflect.ValueOf(signedURLMethods).MapKeys())
|
||||
)
|
||||
|
||||
var userAgent = fmt.Sprintf("gcloud-golang-storage/%s", internal.Version)
|
||||
@@ -233,6 +238,62 @@ func NewGRPCClient(ctx context.Context, opts ...option.ClientOption) (*Client, e
|
||||
return &Client{tc: tc}, nil
|
||||
}
|
||||
|
||||
// CheckDirectConnectivitySupported checks if gRPC direct connectivity
|
||||
// is available for a specific bucket from the environment where the client
|
||||
// is running. A `nil` error represents Direct Connectivity was detected.
|
||||
// Direct connectivity is expected to be available when running from inside
|
||||
// GCP and connecting to a bucket in the same region.
|
||||
//
|
||||
// Experimental helper that's subject to change.
|
||||
//
|
||||
// You can pass in [option.ClientOption] you plan on passing to [NewGRPCClient]
|
||||
func CheckDirectConnectivitySupported(ctx context.Context, bucket string, opts ...option.ClientOption) error {
|
||||
view := metric.NewView(
|
||||
metric.Instrument{
|
||||
Name: "grpc.client.attempt.duration",
|
||||
Kind: metric.InstrumentKindHistogram,
|
||||
},
|
||||
metric.Stream{AttributeFilter: attribute.NewAllowKeysFilter("grpc.lb.locality")},
|
||||
)
|
||||
mr := metric.NewManualReader()
|
||||
provider := metric.NewMeterProvider(metric.WithReader(mr), metric.WithView(view))
|
||||
// Provider handles shutting down ManualReader
|
||||
defer provider.Shutdown(ctx)
|
||||
mo := opentelemetry.MetricsOptions{
|
||||
MeterProvider: provider,
|
||||
Metrics: stats.NewMetrics("grpc.client.attempt.duration"),
|
||||
OptionalLabels: []string{"grpc.lb.locality"},
|
||||
}
|
||||
combinedOpts := append(opts, WithDisabledClientMetrics(), option.WithGRPCDialOption(opentelemetry.DialOption(opentelemetry.Options{MetricsOptions: mo})))
|
||||
client, err := NewGRPCClient(ctx, combinedOpts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("storage.NewGRPCClient: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
if _, err = client.Bucket(bucket).Attrs(ctx); err != nil {
|
||||
return fmt.Errorf("Bucket.Attrs: %w", err)
|
||||
}
|
||||
// Call manual reader to collect metric
|
||||
rm := metricdata.ResourceMetrics{}
|
||||
if err = mr.Collect(context.Background(), &rm); err != nil {
|
||||
return fmt.Errorf("ManualReader.Collect: %w", err)
|
||||
}
|
||||
for _, sm := range rm.ScopeMetrics {
|
||||
for _, m := range sm.Metrics {
|
||||
if m.Name == "grpc.client.attempt.duration" {
|
||||
hist := m.Data.(metricdata.Histogram[float64])
|
||||
for _, d := range hist.DataPoints {
|
||||
v, present := d.Attributes.Value("grpc.lb.locality")
|
||||
if present && v.AsString() != "" && v.AsString() != "{}" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("storage: direct connectivity not detected")
|
||||
}
|
||||
|
||||
// Close closes the Client.
|
||||
//
|
||||
// Close need not be called at program exit.
|
||||
@@ -628,7 +689,7 @@ func validateOptions(opts *SignedURLOptions, now time.Time) error {
|
||||
}
|
||||
opts.Method = strings.ToUpper(opts.Method)
|
||||
if _, ok := signedURLMethods[opts.Method]; !ok {
|
||||
return errMethodNotValid
|
||||
return errSignedURLMethodNotValid
|
||||
}
|
||||
if opts.Expires.IsZero() {
|
||||
return errors.New("storage: missing required expires option")
|
||||
@@ -876,6 +937,9 @@ func signedURLV2(bucket, name string, opts *SignedURLOptions) (string, error) {
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// ReadHandle associated with the object. This is periodically refreshed.
|
||||
type ReadHandle []byte
|
||||
|
||||
// ObjectHandle provides operations on an object in a Google Cloud Storage bucket.
|
||||
// Use BucketHandle.Object to get a handle.
|
||||
type ObjectHandle struct {
|
||||
@@ -891,6 +955,23 @@ type ObjectHandle struct {
|
||||
retry *retryConfig
|
||||
overrideRetention *bool
|
||||
softDeleted bool
|
||||
readHandle ReadHandle
|
||||
}
|
||||
|
||||
// ReadHandle returns a new ObjectHandle that uses the ReadHandle to open the objects.
|
||||
//
|
||||
// Objects that have already been opened can be opened an additional time,
|
||||
// using a read handle returned in the response, at lower latency.
|
||||
// This produces the exact same object and generation and does not check if
|
||||
// the generation is still the newest one.
|
||||
// Note that this will be a noop unless it's set on a gRPC client on buckets with
|
||||
// bi-directional read API access.
|
||||
// Also note that you can get a ReadHandle only via calling reader.ReadHandle() on a
|
||||
// previous read of the same object.
|
||||
func (o *ObjectHandle) ReadHandle(r ReadHandle) *ObjectHandle {
|
||||
o2 := *o
|
||||
o2.readHandle = r
|
||||
return &o2
|
||||
}
|
||||
|
||||
// ACL provides access to the object's access control list.
|
||||
@@ -1095,6 +1176,38 @@ func (o *ObjectHandle) Restore(ctx context.Context, opts *RestoreOptions) (*Obje
|
||||
}, sOpts...)
|
||||
}
|
||||
|
||||
// Move changes the name of the object to the destination name.
|
||||
// It can only be used to rename an object within the same bucket. The
|
||||
// bucket must have [HierarchicalNamespace] enabled to use this method.
|
||||
//
|
||||
// Any preconditions set on the ObjectHandle will be applied for the source
|
||||
// object. Set preconditions on the destination object using
|
||||
// [MoveObjectDestination.Conditions].
|
||||
//
|
||||
// This API is in preview and is not yet publicly available.
|
||||
func (o *ObjectHandle) Move(ctx context.Context, destination MoveObjectDestination) (*ObjectAttrs, error) {
|
||||
if err := o.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sOpts := makeStorageOpts(true, o.retry, o.userProject)
|
||||
return o.c.tc.MoveObject(ctx, &moveObjectParams{
|
||||
bucket: o.bucket,
|
||||
srcObject: o.object,
|
||||
dstObject: destination.Object,
|
||||
srcConds: o.conds,
|
||||
dstConds: destination.Conditions,
|
||||
encryptionKey: o.encryptionKey,
|
||||
}, sOpts...)
|
||||
}
|
||||
|
||||
// MoveObjectDestination provides the destination object name and (optional) preconditions
|
||||
// for [ObjectHandle.Move].
|
||||
type MoveObjectDestination struct {
|
||||
Object string
|
||||
Conditions *Conditions
|
||||
}
|
||||
|
||||
// NewWriter returns a storage Writer that writes to the GCS object
|
||||
// associated with this ObjectHandle.
|
||||
//
|
||||
@@ -1994,56 +2107,91 @@ func applyConds(method string, gen int64, conds *Conditions, call interface{}) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func applySourceConds(gen int64, conds *Conditions, call *raw.ObjectsRewriteCall) error {
|
||||
// applySourceConds modifies the provided call using the conditions in conds.
|
||||
// call is something that quacks like a *raw.WhateverCall.
|
||||
// This is specifically for calls like Rewrite and Move which have a source and destination
|
||||
// object.
|
||||
func applySourceConds(method string, gen int64, conds *Conditions, call interface{}) error {
|
||||
cval := reflect.ValueOf(call)
|
||||
if gen >= 0 {
|
||||
call.SourceGeneration(gen)
|
||||
if !setSourceGeneration(cval, gen) {
|
||||
return fmt.Errorf("storage: %s: source generation not supported", method)
|
||||
}
|
||||
}
|
||||
if conds == nil {
|
||||
return nil
|
||||
}
|
||||
if err := conds.validate("CopyTo source"); err != nil {
|
||||
if err := conds.validate(method); err != nil {
|
||||
return err
|
||||
}
|
||||
switch {
|
||||
case conds.GenerationMatch != 0:
|
||||
call.IfSourceGenerationMatch(conds.GenerationMatch)
|
||||
if !setIfSourceGenerationMatch(cval, conds.GenerationMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceGenerationMatch not supported", method)
|
||||
}
|
||||
case conds.GenerationNotMatch != 0:
|
||||
call.IfSourceGenerationNotMatch(conds.GenerationNotMatch)
|
||||
if !setIfSourceGenerationNotMatch(cval, conds.GenerationNotMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceGenerationNotMatch not supported", method)
|
||||
}
|
||||
case conds.DoesNotExist:
|
||||
call.IfSourceGenerationMatch(0)
|
||||
if !setIfSourceGenerationMatch(cval, int64(0)) {
|
||||
return fmt.Errorf("storage: %s: DoesNotExist not supported", method)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case conds.MetagenerationMatch != 0:
|
||||
call.IfSourceMetagenerationMatch(conds.MetagenerationMatch)
|
||||
if !setIfSourceMetagenerationMatch(cval, conds.MetagenerationMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceMetagenerationMatch not supported", method)
|
||||
}
|
||||
case conds.MetagenerationNotMatch != 0:
|
||||
call.IfSourceMetagenerationNotMatch(conds.MetagenerationNotMatch)
|
||||
if !setIfSourceMetagenerationNotMatch(cval, conds.MetagenerationNotMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceMetagenerationNotMatch not supported", method)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applySourceCondsProto(gen int64, conds *Conditions, call *storagepb.RewriteObjectRequest) error {
|
||||
// applySourceCondsProto validates and attempts to set the conditions on a protobuf
|
||||
// message using protobuf reflection. This is specifically for RPCs which have separate
|
||||
// preconditions for source and destination objects (e.g. Rewrite and Move).
|
||||
func applySourceCondsProto(method string, gen int64, conds *Conditions, msg proto.Message) error {
|
||||
rmsg := msg.ProtoReflect()
|
||||
|
||||
if gen >= 0 {
|
||||
call.SourceGeneration = gen
|
||||
if !setConditionProtoField(rmsg, "source_generation", gen) {
|
||||
return fmt.Errorf("storage: %s: generation not supported", method)
|
||||
}
|
||||
}
|
||||
if conds == nil {
|
||||
return nil
|
||||
}
|
||||
if err := conds.validate("CopyTo source"); err != nil {
|
||||
if err := conds.validate(method); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case conds.GenerationMatch != 0:
|
||||
call.IfSourceGenerationMatch = proto.Int64(conds.GenerationMatch)
|
||||
if !setConditionProtoField(rmsg, "if_source_generation_match", conds.GenerationMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceGenerationMatch not supported", method)
|
||||
}
|
||||
case conds.GenerationNotMatch != 0:
|
||||
call.IfSourceGenerationNotMatch = proto.Int64(conds.GenerationNotMatch)
|
||||
if !setConditionProtoField(rmsg, "if_source_generation_not_match", conds.GenerationNotMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceGenerationNotMatch not supported", method)
|
||||
}
|
||||
case conds.DoesNotExist:
|
||||
call.IfSourceGenerationMatch = proto.Int64(0)
|
||||
if !setConditionProtoField(rmsg, "if_source_generation_match", int64(0)) {
|
||||
return fmt.Errorf("storage: %s: DoesNotExist not supported", method)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case conds.MetagenerationMatch != 0:
|
||||
call.IfSourceMetagenerationMatch = proto.Int64(conds.MetagenerationMatch)
|
||||
if !setConditionProtoField(rmsg, "if_source_metageneration_match", conds.MetagenerationMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceMetagenerationMatch not supported", method)
|
||||
}
|
||||
case conds.MetagenerationNotMatch != 0:
|
||||
call.IfSourceMetagenerationNotMatch = proto.Int64(conds.MetagenerationNotMatch)
|
||||
if !setConditionProtoField(rmsg, "if_source_metageneration_not_match", conds.MetagenerationNotMatch) {
|
||||
return fmt.Errorf("storage: %s: ifSourceMetagenerationNotMatch not supported", method)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -2082,6 +2230,27 @@ func setIfMetagenerationNotMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfMetagenerationNotMatch"), value)
|
||||
}
|
||||
|
||||
// More methods to set source object precondition fields (used by Rewrite and Move APIs).
|
||||
func setSourceGeneration(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("SourceGeneration"), value)
|
||||
}
|
||||
|
||||
func setIfSourceGenerationMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfSourceGenerationMatch"), value)
|
||||
}
|
||||
|
||||
func setIfSourceGenerationNotMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfSourceGenerationNotMatch"), value)
|
||||
}
|
||||
|
||||
func setIfSourceMetagenerationMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfSourceMetagenerationMatch"), value)
|
||||
}
|
||||
|
||||
func setIfSourceMetagenerationNotMatch(cval reflect.Value, value interface{}) bool {
|
||||
return setCondition(cval.MethodByName("IfSourceMetagenerationNotMatch"), value)
|
||||
}
|
||||
|
||||
func setCondition(setter reflect.Value, value interface{}) bool {
|
||||
if setter.IsValid() {
|
||||
setter.Call([]reflect.Value{reflect.ValueOf(value)})
|
||||
|
||||
+20
@@ -88,11 +88,29 @@ type Writer struct {
|
||||
// cancellation.
|
||||
ChunkRetryDeadline time.Duration
|
||||
|
||||
// ChunkTransferTimeout sets a per-chunk request timeout for resumable uploads.
|
||||
//
|
||||
// For resumable uploads, the Writer will terminate the request and attempt a retry
|
||||
// if the request to upload a particular chunk stalls for longer than this duration. Retries
|
||||
// may continue until the ChunkRetryDeadline is reached.
|
||||
//
|
||||
// The default value is no timeout.
|
||||
ChunkTransferTimeout time.Duration
|
||||
|
||||
// ForceEmptyContentType is an optional parameter that is used to disable
|
||||
// auto-detection of Content-Type. By default, if a blank Content-Type
|
||||
// is provided, then gax.DetermineContentType is called to sniff the type.
|
||||
ForceEmptyContentType bool
|
||||
|
||||
// Append is a parameter to indicate whether the writer should use appendable
|
||||
// object semantics for the new object generation. Appendable objects are
|
||||
// visible on the first Write() call, and can be appended to until they are
|
||||
// finalized. The object is finalized on a call to Close().
|
||||
//
|
||||
// Append is only supported for gRPC. This feature is in preview and is not
|
||||
// yet available for general use.
|
||||
Append bool
|
||||
|
||||
// ProgressFunc can be used to monitor the progress of a large write
|
||||
// operation. If ProgressFunc is not nil and writing requires multiple
|
||||
// calls to the underlying service (see
|
||||
@@ -188,11 +206,13 @@ func (w *Writer) openWriter() (err error) {
|
||||
ctx: w.ctx,
|
||||
chunkSize: w.ChunkSize,
|
||||
chunkRetryDeadline: w.ChunkRetryDeadline,
|
||||
chunkTransferTimeout: w.ChunkTransferTimeout,
|
||||
bucket: w.o.bucket,
|
||||
attrs: &w.ObjectAttrs,
|
||||
conds: w.o.conds,
|
||||
encryptionKey: w.o.encryptionKey,
|
||||
sendCRC32C: w.SendCRC32C,
|
||||
append: w.Append,
|
||||
donec: w.donec,
|
||||
setError: w.error,
|
||||
progress: w.progress,
|
||||
|
||||
Generated
Vendored
+3
-1
@@ -14,6 +14,8 @@
|
||||
|
||||
package gcp
|
||||
|
||||
import "context"
|
||||
|
||||
const (
|
||||
// See https://cloud.google.com/appengine/docs/flexible/python/migrating#modules
|
||||
// for the environment variables available in GAE environments.
|
||||
@@ -67,7 +69,7 @@ func (d *Detector) AppEngineFlexAvailabilityZoneAndRegion() (string, string, err
|
||||
|
||||
// AppEngineStandardAvailabilityZone returns the zone the app engine service is running in.
|
||||
func (d *Detector) AppEngineStandardAvailabilityZone() (string, error) {
|
||||
return d.metadata.Zone()
|
||||
return d.metadata.ZoneWithContext(context.TODO())
|
||||
}
|
||||
|
||||
// AppEngineStandardCloudRegion returns the region the app engine service is running in.
|
||||
|
||||
Generated
Vendored
+13
-14
@@ -15,8 +15,10 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
)
|
||||
@@ -68,27 +70,24 @@ func (d *Detector) CloudPlatform() Platform {
|
||||
|
||||
// ProjectID returns the ID of the project in which this program is running.
|
||||
func (d *Detector) ProjectID() (string, error) {
|
||||
return d.metadata.ProjectID()
|
||||
// N.B. d.metadata.ProjectIDWithContext(context.TODO()) is cached globally, so if we use it here it's untestable.
|
||||
s, err := d.metadata.GetWithContext(context.TODO(), "project/project-id")
|
||||
return strings.TrimSpace(s), err
|
||||
}
|
||||
|
||||
// instanceID returns the ID of the project in which this program is running.
|
||||
func (d *Detector) instanceID() (string, error) {
|
||||
// N.B. d.metadata.InstanceIDWithContext(context.TODO()) is cached globally, so if we use it here it's untestable.
|
||||
s, err := d.metadata.GetWithContext(context.TODO(), "instance/id")
|
||||
return strings.TrimSpace(s), err
|
||||
}
|
||||
|
||||
// Detector collects resource information for all GCP platforms.
|
||||
type Detector struct {
|
||||
metadata metadataProvider
|
||||
metadata *metadata.Client
|
||||
os osProvider
|
||||
}
|
||||
|
||||
// metadataProvider contains the subset of the metadata.Client functions used
|
||||
// by this resource Detector to allow testing with a fake implementation.
|
||||
type metadataProvider interface {
|
||||
ProjectID() (string, error)
|
||||
InstanceID() (string, error)
|
||||
Get(string) (string, error)
|
||||
InstanceName() (string, error)
|
||||
Hostname() (string, error)
|
||||
Zone() (string, error)
|
||||
InstanceAttributeValue(string) (string, error)
|
||||
}
|
||||
|
||||
// osProvider contains the subset of the os package functions used by.
|
||||
type osProvider interface {
|
||||
LookupEnv(string) (string, bool)
|
||||
|
||||
Generated
Vendored
+3
-2
@@ -15,6 +15,7 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -89,7 +90,7 @@ func (d *Detector) CloudRunJobTaskIndex() (string, error) {
|
||||
|
||||
// FaaSID returns the instance id of the Cloud Run or Cloud Function.
|
||||
func (d *Detector) FaaSID() (string, error) {
|
||||
return d.metadata.InstanceID()
|
||||
return d.instanceID()
|
||||
}
|
||||
|
||||
// FaaSCloudRegion detects region from the metadata server.
|
||||
@@ -97,7 +98,7 @@ func (d *Detector) FaaSID() (string, error) {
|
||||
//
|
||||
// https://cloud.google.com/run/docs/reference/container-contract#metadata-server
|
||||
func (d *Detector) FaaSCloudRegion() (string, error) {
|
||||
region, err := d.metadata.Get(regionMetadataAttr)
|
||||
region, err := d.metadata.GetWithContext(context.TODO(), regionMetadataAttr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
Generated
Vendored
+50
-8
@@ -15,52 +15,59 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"cloud.google.com/go/compute/metadata"
|
||||
)
|
||||
|
||||
// See the available GCE instance metadata:
|
||||
// https://cloud.google.com/compute/docs/metadata/default-metadata-values#vm_instance_metadata
|
||||
// https://cloud.google.com/compute/docs/metadata/predefined-metadata-keys#instance-metadata
|
||||
const machineTypeMetadataAttr = "instance/machine-type"
|
||||
|
||||
// https://cloud.google.com/compute/docs/instance-groups/getting-info-about-migs#checking_if_a_vm_instance_is_part_of_a_mig
|
||||
const createdByInstanceAttr = "created-by"
|
||||
|
||||
func (d *Detector) onGCE() bool {
|
||||
_, err := d.metadata.Get(machineTypeMetadataAttr)
|
||||
_, err := d.metadata.GetWithContext(context.TODO(), machineTypeMetadataAttr)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// GCEHostType returns the machine type of the instance on which this program is running.
|
||||
func (d *Detector) GCEHostType() (string, error) {
|
||||
return d.metadata.Get(machineTypeMetadataAttr)
|
||||
return d.metadata.GetWithContext(context.TODO(), machineTypeMetadataAttr)
|
||||
}
|
||||
|
||||
// GCEHostID returns the instance ID of the instance on which this program is running.
|
||||
func (d *Detector) GCEHostID() (string, error) {
|
||||
return d.metadata.InstanceID()
|
||||
return d.instanceID()
|
||||
}
|
||||
|
||||
// GCEHostName returns the instance name of the instance on which this program is running.
|
||||
// Recommended to use GCEInstanceName() or GCEInstanceHostname() to more accurately reflect which
|
||||
// value is returned.
|
||||
func (d *Detector) GCEHostName() (string, error) {
|
||||
return d.metadata.InstanceName()
|
||||
return d.metadata.InstanceNameWithContext(context.TODO())
|
||||
}
|
||||
|
||||
// GCEInstanceName returns the instance name of the instance on which this program is running.
|
||||
// This is the value visible in the Cloud Console UI, and the prefix for the default hostname
|
||||
// of the instance as defined by the default internal DNS name (see https://cloud.google.com/compute/docs/internal-dns#instance-fully-qualified-domain-names).
|
||||
func (d *Detector) GCEInstanceName() (string, error) {
|
||||
return d.metadata.InstanceName()
|
||||
return d.metadata.InstanceNameWithContext(context.TODO())
|
||||
}
|
||||
|
||||
// GCEInstanceHostname returns the full value of the default or custom hostname of the instance
|
||||
// on which this program is running. See https://cloud.google.com/compute/docs/instances/custom-hostname-vm.
|
||||
func (d *Detector) GCEInstanceHostname() (string, error) {
|
||||
return d.metadata.Hostname()
|
||||
return d.metadata.HostnameWithContext(context.TODO())
|
||||
}
|
||||
|
||||
// GCEAvailabilityZoneAndRegion returns the zone and region in which this program is running.
|
||||
func (d *Detector) GCEAvailabilityZoneAndRegion() (string, string, error) {
|
||||
zone, err := d.metadata.Zone()
|
||||
zone, err := d.metadata.ZoneWithContext(context.TODO())
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -73,3 +80,38 @@ func (d *Detector) GCEAvailabilityZoneAndRegion() (string, string, error) {
|
||||
}
|
||||
return zone, strings.Join(splitZone[0:2], "-"), nil
|
||||
}
|
||||
|
||||
type ManagedInstanceGroup struct {
|
||||
Name string
|
||||
Location string
|
||||
Type LocationType
|
||||
}
|
||||
|
||||
var createdByMIGRE = regexp.MustCompile(`^projects/[^/]+/(zones|regions)/([^/]+)/instanceGroupManagers/([^/]+)$`)
|
||||
|
||||
func (d *Detector) GCEManagedInstanceGroup() (ManagedInstanceGroup, error) {
|
||||
createdBy, err := d.metadata.InstanceAttributeValueWithContext(context.TODO(), createdByInstanceAttr)
|
||||
if _, ok := err.(metadata.NotDefinedError); ok {
|
||||
return ManagedInstanceGroup{}, nil
|
||||
} else if err != nil {
|
||||
return ManagedInstanceGroup{}, err
|
||||
}
|
||||
matches := createdByMIGRE.FindStringSubmatch(createdBy)
|
||||
if matches == nil {
|
||||
// The "created-by" key exists, but it doesn't describe a MIG.
|
||||
// Something else must have created this VM.
|
||||
return ManagedInstanceGroup{}, nil
|
||||
}
|
||||
|
||||
mig := ManagedInstanceGroup{
|
||||
Name: matches[3],
|
||||
Location: matches[2],
|
||||
}
|
||||
switch matches[1] {
|
||||
case "zones":
|
||||
mig.Type = Zone
|
||||
case "regions":
|
||||
mig.Type = Region
|
||||
}
|
||||
return mig, nil
|
||||
}
|
||||
Generated
Vendored
+11
-3
@@ -15,6 +15,7 @@
|
||||
package gcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
@@ -31,8 +32,15 @@ const (
|
||||
)
|
||||
|
||||
func (d *Detector) onGKE() bool {
|
||||
// Check if we are on k8s first
|
||||
_, found := d.os.LookupEnv(k8sServiceHostEnv)
|
||||
return found
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
// If we are on k8s, make sure that we are actually on GKE, and not a
|
||||
// different managed k8s platform.
|
||||
_, err := d.metadata.InstanceAttributeValueWithContext(context.TODO(), clusterLocationMetadataAttr)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// GKEHostID returns the instance ID of the instance on which this program is running.
|
||||
@@ -42,7 +50,7 @@ func (d *Detector) GKEHostID() (string, error) {
|
||||
|
||||
// GKEClusterName returns the name if the GKE cluster in which this program is running.
|
||||
func (d *Detector) GKEClusterName() (string, error) {
|
||||
return d.metadata.InstanceAttributeValue(clusterNameMetadataAttr)
|
||||
return d.metadata.InstanceAttributeValueWithContext(context.TODO(), clusterNameMetadataAttr)
|
||||
}
|
||||
|
||||
type LocationType int64
|
||||
@@ -55,7 +63,7 @@ const (
|
||||
|
||||
// GKEAvailabilityZoneOrRegion returns the location of the cluster and whether the cluster is zonal or regional.
|
||||
func (d *Detector) GKEAvailabilityZoneOrRegion() (string, LocationType, error) {
|
||||
clusterLocation, err := d.metadata.InstanceAttributeValue(clusterLocationMetadataAttr)
|
||||
clusterLocation, err := d.metadata.InstanceAttributeValueWithContext(context.TODO(), clusterLocationMetadataAttr)
|
||||
if err != nil {
|
||||
return "", UndefinedLocation, err
|
||||
}
|
||||
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BackOffContext is a backoff policy that stops retrying after the context
|
||||
// is canceled.
|
||||
type BackOffContext interface { // nolint: golint
|
||||
BackOff
|
||||
Context() context.Context
|
||||
}
|
||||
|
||||
type backOffContext struct {
|
||||
BackOff
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// WithContext returns a BackOffContext with context ctx
|
||||
//
|
||||
// ctx must not be nil
|
||||
func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint
|
||||
if ctx == nil {
|
||||
panic("nil context")
|
||||
}
|
||||
|
||||
if b, ok := b.(*backOffContext); ok {
|
||||
return &backOffContext{
|
||||
BackOff: b.BackOff,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
return &backOffContext{
|
||||
BackOff: b,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
func getContext(b BackOff) context.Context {
|
||||
if cb, ok := b.(BackOffContext); ok {
|
||||
return cb.Context()
|
||||
}
|
||||
if tb, ok := b.(*backOffTries); ok {
|
||||
return getContext(tb.delegate)
|
||||
}
|
||||
return context.Background()
|
||||
}
|
||||
|
||||
func (b *backOffContext) Context() context.Context {
|
||||
return b.ctx
|
||||
}
|
||||
|
||||
func (b *backOffContext) NextBackOff() time.Duration {
|
||||
select {
|
||||
case <-b.ctx.Done():
|
||||
return Stop
|
||||
default:
|
||||
return b.BackOff.NextBackOff()
|
||||
}
|
||||
}
|
||||
-216
@@ -1,216 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
ExponentialBackOff is a backoff implementation that increases the backoff
|
||||
period for each retry attempt using a randomization function that grows exponentially.
|
||||
|
||||
NextBackOff() is calculated using the following formula:
|
||||
|
||||
randomized interval =
|
||||
RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
|
||||
|
||||
In other words NextBackOff() will range between the randomization factor
|
||||
percentage below and above the retry interval.
|
||||
|
||||
For example, given the following parameters:
|
||||
|
||||
RetryInterval = 2
|
||||
RandomizationFactor = 0.5
|
||||
Multiplier = 2
|
||||
|
||||
the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
|
||||
multiplied by the exponential, that is, between 2 and 6 seconds.
|
||||
|
||||
Note: MaxInterval caps the RetryInterval and not the randomized interval.
|
||||
|
||||
If the time elapsed since an ExponentialBackOff instance is created goes past the
|
||||
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
|
||||
|
||||
The elapsed time can be reset by calling Reset().
|
||||
|
||||
Example: Given the following default arguments, for 10 tries the sequence will be,
|
||||
and assuming we go over the MaxElapsedTime on the 10th try:
|
||||
|
||||
Request # RetryInterval (seconds) Randomized Interval (seconds)
|
||||
|
||||
1 0.5 [0.25, 0.75]
|
||||
2 0.75 [0.375, 1.125]
|
||||
3 1.125 [0.562, 1.687]
|
||||
4 1.687 [0.8435, 2.53]
|
||||
5 2.53 [1.265, 3.795]
|
||||
6 3.795 [1.897, 5.692]
|
||||
7 5.692 [2.846, 8.538]
|
||||
8 8.538 [4.269, 12.807]
|
||||
9 12.807 [6.403, 19.210]
|
||||
10 19.210 backoff.Stop
|
||||
|
||||
Note: Implementation is not thread-safe.
|
||||
*/
|
||||
type ExponentialBackOff struct {
|
||||
InitialInterval time.Duration
|
||||
RandomizationFactor float64
|
||||
Multiplier float64
|
||||
MaxInterval time.Duration
|
||||
// After MaxElapsedTime the ExponentialBackOff returns Stop.
|
||||
// It never stops if MaxElapsedTime == 0.
|
||||
MaxElapsedTime time.Duration
|
||||
Stop time.Duration
|
||||
Clock Clock
|
||||
|
||||
currentInterval time.Duration
|
||||
startTime time.Time
|
||||
}
|
||||
|
||||
// Clock is an interface that returns current time for BackOff.
|
||||
type Clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
// ExponentialBackOffOpts is a function type used to configure ExponentialBackOff options.
|
||||
type ExponentialBackOffOpts func(*ExponentialBackOff)
|
||||
|
||||
// Default values for ExponentialBackOff.
|
||||
const (
|
||||
DefaultInitialInterval = 500 * time.Millisecond
|
||||
DefaultRandomizationFactor = 0.5
|
||||
DefaultMultiplier = 1.5
|
||||
DefaultMaxInterval = 60 * time.Second
|
||||
DefaultMaxElapsedTime = 15 * time.Minute
|
||||
)
|
||||
|
||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
|
||||
func NewExponentialBackOff(opts ...ExponentialBackOffOpts) *ExponentialBackOff {
|
||||
b := &ExponentialBackOff{
|
||||
InitialInterval: DefaultInitialInterval,
|
||||
RandomizationFactor: DefaultRandomizationFactor,
|
||||
Multiplier: DefaultMultiplier,
|
||||
MaxInterval: DefaultMaxInterval,
|
||||
MaxElapsedTime: DefaultMaxElapsedTime,
|
||||
Stop: Stop,
|
||||
Clock: SystemClock,
|
||||
}
|
||||
for _, fn := range opts {
|
||||
fn(b)
|
||||
}
|
||||
b.Reset()
|
||||
return b
|
||||
}
|
||||
|
||||
// WithInitialInterval sets the initial interval between retries.
|
||||
func WithInitialInterval(duration time.Duration) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.InitialInterval = duration
|
||||
}
|
||||
}
|
||||
|
||||
// WithRandomizationFactor sets the randomization factor to add jitter to intervals.
|
||||
func WithRandomizationFactor(randomizationFactor float64) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.RandomizationFactor = randomizationFactor
|
||||
}
|
||||
}
|
||||
|
||||
// WithMultiplier sets the multiplier for increasing the interval after each retry.
|
||||
func WithMultiplier(multiplier float64) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.Multiplier = multiplier
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxInterval sets the maximum interval between retries.
|
||||
func WithMaxInterval(duration time.Duration) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.MaxInterval = duration
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxElapsedTime sets the maximum total time for retries.
|
||||
func WithMaxElapsedTime(duration time.Duration) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.MaxElapsedTime = duration
|
||||
}
|
||||
}
|
||||
|
||||
// WithRetryStopDuration sets the duration after which retries should stop.
|
||||
func WithRetryStopDuration(duration time.Duration) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.Stop = duration
|
||||
}
|
||||
}
|
||||
|
||||
// WithClockProvider sets the clock used to measure time.
|
||||
func WithClockProvider(clock Clock) ExponentialBackOffOpts {
|
||||
return func(ebo *ExponentialBackOff) {
|
||||
ebo.Clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
type systemClock struct{}
|
||||
|
||||
func (t systemClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// SystemClock implements Clock interface that uses time.Now().
|
||||
var SystemClock = systemClock{}
|
||||
|
||||
// Reset the interval back to the initial retry interval and restarts the timer.
|
||||
// Reset must be called before using b.
|
||||
func (b *ExponentialBackOff) Reset() {
|
||||
b.currentInterval = b.InitialInterval
|
||||
b.startTime = b.Clock.Now()
|
||||
}
|
||||
|
||||
// NextBackOff calculates the next backoff interval using the formula:
|
||||
// Randomized interval = RetryInterval * (1 ± RandomizationFactor)
|
||||
func (b *ExponentialBackOff) NextBackOff() time.Duration {
|
||||
// Make sure we have not gone over the maximum elapsed time.
|
||||
elapsed := b.GetElapsedTime()
|
||||
next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
|
||||
b.incrementCurrentInterval()
|
||||
if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime {
|
||||
return b.Stop
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
|
||||
// is created and is reset when Reset() is called.
|
||||
//
|
||||
// The elapsed time is computed using time.Now().UnixNano(). It is
|
||||
// safe to call even while the backoff policy is used by a running
|
||||
// ticker.
|
||||
func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
|
||||
return b.Clock.Now().Sub(b.startTime)
|
||||
}
|
||||
|
||||
// Increments the current interval by multiplying it with the multiplier.
|
||||
func (b *ExponentialBackOff) incrementCurrentInterval() {
|
||||
// Check for overflow, if overflow is detected set the current interval to the max interval.
|
||||
if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
|
||||
b.currentInterval = b.MaxInterval
|
||||
} else {
|
||||
b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a random value from the following interval:
|
||||
// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval].
|
||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
|
||||
if randomizationFactor == 0 {
|
||||
return currentInterval // make sure no randomness is used when randomizationFactor is 0.
|
||||
}
|
||||
var delta = randomizationFactor * float64(currentInterval)
|
||||
var minInterval = float64(currentInterval) - delta
|
||||
var maxInterval = float64(currentInterval) + delta
|
||||
|
||||
// Get a random value from the range [minInterval, maxInterval].
|
||||
// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
|
||||
// we want a 33% chance for selecting either 1, 2 or 3.
|
||||
return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
|
||||
}
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// An OperationWithData is executing by RetryWithData() or RetryNotifyWithData().
|
||||
// The operation will be retried using a backoff policy if it returns an error.
|
||||
type OperationWithData[T any] func() (T, error)
|
||||
|
||||
// An Operation is executing by Retry() or RetryNotify().
|
||||
// The operation will be retried using a backoff policy if it returns an error.
|
||||
type Operation func() error
|
||||
|
||||
func (o Operation) withEmptyData() OperationWithData[struct{}] {
|
||||
return func() (struct{}, error) {
|
||||
return struct{}{}, o()
|
||||
}
|
||||
}
|
||||
|
||||
// Notify is a notify-on-error function. It receives an operation error and
|
||||
// backoff delay if the operation failed (with an error).
|
||||
//
|
||||
// NOTE that if the backoff policy stated to stop retrying,
|
||||
// the notify function isn't called.
|
||||
type Notify func(error, time.Duration)
|
||||
|
||||
// Retry the operation o until it does not return error or BackOff stops.
|
||||
// o is guaranteed to be run at least once.
|
||||
//
|
||||
// If o returns a *PermanentError, the operation is not retried, and the
|
||||
// wrapped error is returned.
|
||||
//
|
||||
// Retry sleeps the goroutine for the duration returned by BackOff after a
|
||||
// failed operation returns.
|
||||
func Retry(o Operation, b BackOff) error {
|
||||
return RetryNotify(o, b, nil)
|
||||
}
|
||||
|
||||
// RetryWithData is like Retry but returns data in the response too.
|
||||
func RetryWithData[T any](o OperationWithData[T], b BackOff) (T, error) {
|
||||
return RetryNotifyWithData(o, b, nil)
|
||||
}
|
||||
|
||||
// RetryNotify calls notify function with the error and wait duration
|
||||
// for each failed attempt before sleep.
|
||||
func RetryNotify(operation Operation, b BackOff, notify Notify) error {
|
||||
return RetryNotifyWithTimer(operation, b, notify, nil)
|
||||
}
|
||||
|
||||
// RetryNotifyWithData is like RetryNotify but returns data in the response too.
|
||||
func RetryNotifyWithData[T any](operation OperationWithData[T], b BackOff, notify Notify) (T, error) {
|
||||
return doRetryNotify(operation, b, notify, nil)
|
||||
}
|
||||
|
||||
// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer
|
||||
// for each failed attempt before sleep.
|
||||
// A default timer that uses system timer is used when nil is passed.
|
||||
func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error {
|
||||
_, err := doRetryNotify(operation.withEmptyData(), b, notify, t)
|
||||
return err
|
||||
}
|
||||
|
||||
// RetryNotifyWithTimerAndData is like RetryNotifyWithTimer but returns data in the response too.
|
||||
func RetryNotifyWithTimerAndData[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
|
||||
return doRetryNotify(operation, b, notify, t)
|
||||
}
|
||||
|
||||
func doRetryNotify[T any](operation OperationWithData[T], b BackOff, notify Notify, t Timer) (T, error) {
|
||||
var (
|
||||
err error
|
||||
next time.Duration
|
||||
res T
|
||||
)
|
||||
if t == nil {
|
||||
t = &defaultTimer{}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
t.Stop()
|
||||
}()
|
||||
|
||||
ctx := getContext(b)
|
||||
|
||||
b.Reset()
|
||||
for {
|
||||
res, err = operation()
|
||||
if err == nil {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
var permanent *PermanentError
|
||||
if errors.As(err, &permanent) {
|
||||
return res, permanent.Err
|
||||
}
|
||||
|
||||
if next = b.NextBackOff(); next == Stop {
|
||||
if cerr := ctx.Err(); cerr != nil {
|
||||
return res, cerr
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
if notify != nil {
|
||||
notify(err, next)
|
||||
}
|
||||
|
||||
t.Start(next)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return res, ctx.Err()
|
||||
case <-t.C():
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PermanentError signals that the operation should not be retried.
|
||||
type PermanentError struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *PermanentError) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *PermanentError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e *PermanentError) Is(target error) bool {
|
||||
_, ok := target.(*PermanentError)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Permanent wraps the given err in a *PermanentError.
|
||||
func Permanent(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &PermanentError{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package backoff
|
||||
|
||||
import "time"
|
||||
|
||||
/*
|
||||
WithMaxRetries creates a wrapper around another BackOff, which will
|
||||
return Stop if NextBackOff() has been called too many times since
|
||||
the last time Reset() was called
|
||||
|
||||
Note: Implementation is not thread-safe.
|
||||
*/
|
||||
func WithMaxRetries(b BackOff, max uint64) BackOff {
|
||||
return &backOffTries{delegate: b, maxTries: max}
|
||||
}
|
||||
|
||||
type backOffTries struct {
|
||||
delegate BackOff
|
||||
maxTries uint64
|
||||
numTries uint64
|
||||
}
|
||||
|
||||
func (b *backOffTries) NextBackOff() time.Duration {
|
||||
if b.maxTries == 0 {
|
||||
return Stop
|
||||
}
|
||||
if b.maxTries > 0 {
|
||||
if b.maxTries <= b.numTries {
|
||||
return Stop
|
||||
}
|
||||
b.numTries++
|
||||
}
|
||||
return b.delegate.NextBackOff()
|
||||
}
|
||||
|
||||
func (b *backOffTries) Reset() {
|
||||
b.numTries = 0
|
||||
b.delegate.Reset()
|
||||
}
|
||||
Generated
File renamed without changes.
+29
@@ -0,0 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [5.0.0] - 2024-12-19
|
||||
|
||||
### Added
|
||||
|
||||
- RetryAfterError can be returned from an operation to indicate how long to wait before the next retry.
|
||||
|
||||
### Changed
|
||||
|
||||
- Retry function now accepts additional options for specifying max number of tries and max elapsed time.
|
||||
- Retry function now accepts a context.Context.
|
||||
- Operation function signature changed to return result (any type) and error.
|
||||
|
||||
### Removed
|
||||
|
||||
- RetryNotify* and RetryWithData functions. Only single Retry function remains.
|
||||
- Optional arguments from ExponentialBackoff constructor.
|
||||
- Clock and Timer interfaces.
|
||||
|
||||
### Fixed
|
||||
|
||||
- The original error is returned from Retry if there's a PermanentError. (#144)
|
||||
- The Retry function respects the wrapped PermanentError. (#140)
|
||||
Loaded 100 of 1449 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user