deps: update images to 0.94

Signed-off-by: Simon de Vlieger <supakeen@redhat.com>
This commit is contained in:
Simon de Vlieger 2024-10-25 09:00:38 +02:00 committed by Sanne Raymaekers
parent 4f90a757dc
commit bccd1639af
1096 changed files with 411794 additions and 11488 deletions

View file

@ -1,6 +1,51 @@
# Changes
## [1.44.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.43.0...storage/v1.44.0) (2024-10-03)
### Features
* **storage/dataflux:** Add dataflux interface ([#10748](https://github.com/googleapis/google-cloud-go/issues/10748)) ([cb7b0a1](https://github.com/googleapis/google-cloud-go/commit/cb7b0a1b285de9d4182155a123747419232dd35f))
* **storage/dataflux:** Add range_splitter [#10748](https://github.com/googleapis/google-cloud-go/issues/10748) ([#10899](https://github.com/googleapis/google-cloud-go/issues/10899)) ([d49da26](https://github.com/googleapis/google-cloud-go/commit/d49da26be7dc52fad37c392c2876f62b1a5625a2))
* **storage/dataflux:** Add worksteal algorithm to fast-listing ([#10913](https://github.com/googleapis/google-cloud-go/issues/10913)) ([015b52c](https://github.com/googleapis/google-cloud-go/commit/015b52c345df75408be3edcfda96d37145794f9f))
* **storage/internal:** Add managed folder to testIamPermissions method ([2f0aec8](https://github.com/googleapis/google-cloud-go/commit/2f0aec894179304d234be6c792d82cf4336b6d0a))
* **storage/transfermanager:** Add option to StripPrefix on directory download ([#10894](https://github.com/googleapis/google-cloud-go/issues/10894)) ([607534c](https://github.com/googleapis/google-cloud-go/commit/607534cdd5edf2d15d3de891cf6a0b6cbaa7d545))
* **storage/transfermanager:** Add SkipIfExists option ([#10893](https://github.com/googleapis/google-cloud-go/issues/10893)) ([7daa1bd](https://github.com/googleapis/google-cloud-go/commit/7daa1bdc78844adac80f6378b1f6f2dd415b80a8))
* **storage/transfermanager:** Checksum full object downloads ([#10569](https://github.com/googleapis/google-cloud-go/issues/10569)) ([c366c90](https://github.com/googleapis/google-cloud-go/commit/c366c908534ef09442f1f3e8a4f74bd545a474fb))
* **storage:** Add direct google access side-effect imports by default ([#10757](https://github.com/googleapis/google-cloud-go/issues/10757)) ([9ad8324](https://github.com/googleapis/google-cloud-go/commit/9ad83248a7049c82580bc45d9685c329811bce88))
* **storage:** Add full object checksum to reader.Attrs ([#10538](https://github.com/googleapis/google-cloud-go/issues/10538)) ([245d2ea](https://github.com/googleapis/google-cloud-go/commit/245d2eaddb4862da7c8d1892d5d462bf390adb2b))
* **storage:** Add support for Go 1.23 iterators ([84461c0](https://github.com/googleapis/google-cloud-go/commit/84461c0ba464ec2f951987ba60030e37c8a8fc18))
* **storage:** Add update time in bucketAttrs ([#10710](https://github.com/googleapis/google-cloud-go/issues/10710)) ([5f06ae1](https://github.com/googleapis/google-cloud-go/commit/5f06ae1a331c46ded47c96c205b3f1be92d64d29)), refs [#9361](https://github.com/googleapis/google-cloud-go/issues/9361)
* **storage:** GA gRPC client ([#10859](https://github.com/googleapis/google-cloud-go/issues/10859)) ([c7a55a2](https://github.com/googleapis/google-cloud-go/commit/c7a55a26c645905317fe27505d503c338f50ee34))
* **storage:** Introduce gRPC client-side metrics ([#10639](https://github.com/googleapis/google-cloud-go/issues/10639)) ([437bcb1](https://github.com/googleapis/google-cloud-go/commit/437bcb1e0b514959648eed36ba3963aa4fbeffc8))
* **storage:** Support IncludeFoldersAsPrefixes for gRPC ([#10767](https://github.com/googleapis/google-cloud-go/issues/10767)) ([65bcc59](https://github.com/googleapis/google-cloud-go/commit/65bcc59a6c0753f8fbd66c8792bc69300e95ec62))
### Bug Fixes
* **storage/transfermanager:** Correct Attrs.StartOffset for sharded downloads ([#10512](https://github.com/googleapis/google-cloud-go/issues/10512)) ([01a5cbb](https://github.com/googleapis/google-cloud-go/commit/01a5cbba6d9d9f425f045b58fa16d8c85804c29c))
* **storage:** Add retryalways policy to encryption test ([#10644](https://github.com/googleapis/google-cloud-go/issues/10644)) ([59cfd12](https://github.com/googleapis/google-cloud-go/commit/59cfd12ce5650279c99787da4a273db1e3253c76)), refs [#10567](https://github.com/googleapis/google-cloud-go/issues/10567)
* **storage:** Add unknown host to retriable errors ([#10619](https://github.com/googleapis/google-cloud-go/issues/10619)) ([4ec0452](https://github.com/googleapis/google-cloud-go/commit/4ec0452a393341b1036ac6e1e7287843f097d978))
* **storage:** Bump dependencies ([2ddeb15](https://github.com/googleapis/google-cloud-go/commit/2ddeb1544a53188a7592046b98913982f1b0cf04))
* **storage:** Bump google.golang.org/grpc@v1.64.1 ([8ecc4e9](https://github.com/googleapis/google-cloud-go/commit/8ecc4e9622e5bbe9b90384d5848ab816027226c5))
* **storage:** Check for grpc NotFound error in HMAC test ([#10645](https://github.com/googleapis/google-cloud-go/issues/10645)) ([3c8e88a](https://github.com/googleapis/google-cloud-go/commit/3c8e88a085bab3142dfff6ef9a8e49c29a5c877d))
* **storage:** Disable grpc metrics using emulator ([#10870](https://github.com/googleapis/google-cloud-go/issues/10870)) ([35ad73d](https://github.com/googleapis/google-cloud-go/commit/35ad73d3be5485ac592e2ef1ea6c0854f1eff4a0))
* **storage:** Retry gRPC DEADLINE_EXCEEDED errors ([#10635](https://github.com/googleapis/google-cloud-go/issues/10635)) ([0018415](https://github.com/googleapis/google-cloud-go/commit/0018415295a5fd964b923db6a4785e9eed46a2e2))
* **storage:** Update dependencies ([257c40b](https://github.com/googleapis/google-cloud-go/commit/257c40bd6d7e59730017cf32bda8823d7a232758))
* **storage:** Update google.golang.org/api to v0.191.0 ([5b32644](https://github.com/googleapis/google-cloud-go/commit/5b32644eb82eb6bd6021f80b4fad471c60fb9d73))
### Performance Improvements
* **storage:** GRPC zerocopy codec ([#10888](https://github.com/googleapis/google-cloud-go/issues/10888)) ([aeba28f](https://github.com/googleapis/google-cloud-go/commit/aeba28ffffcd82ac5540e45247112bdacc5c530d))
### Documentation
* **storage/internal:** Clarify possible objectAccessControl roles ([2f0aec8](https://github.com/googleapis/google-cloud-go/commit/2f0aec894179304d234be6c792d82cf4336b6d0a))
* **storage/internal:** Update dual-region bucket link ([2f0aec8](https://github.com/googleapis/google-cloud-go/commit/2f0aec894179304d234be6c792d82cf4336b6d0a))
## [1.43.0](https://github.com/googleapis/google-cloud-go/compare/storage/v1.42.0...storage/v1.43.0) (2024-07-03)

View file

@ -416,6 +416,10 @@ type BucketAttrs struct {
// This field is read-only.
Created time.Time
// Updated is the time at which the bucket was last modified.
// This field is read-only.
Updated time.Time
// VersioningEnabled reports whether this bucket has versioning enabled.
VersioningEnabled bool
@ -824,6 +828,7 @@ func newBucket(b *raw.Bucket) (*BucketAttrs, error) {
DefaultEventBasedHold: b.DefaultEventBasedHold,
StorageClass: b.StorageClass,
Created: convertTime(b.TimeCreated),
Updated: convertTime(b.Updated),
VersioningEnabled: b.Versioning != nil && b.Versioning.Enabled,
ACL: toBucketACLRules(b.Acl),
DefaultObjectACL: toObjectACLRules(b.DefaultObjectAcl),
@ -861,6 +866,7 @@ func newBucketFromProto(b *storagepb.Bucket) *BucketAttrs {
DefaultEventBasedHold: b.GetDefaultEventBasedHold(),
StorageClass: b.GetStorageClass(),
Created: b.GetCreateTime().AsTime(),
Updated: b.GetUpdateTime().AsTime(),
VersioningEnabled: b.GetVersioning().GetEnabled(),
ACL: toBucketACLRulesFromProto(b.GetAcl()),
DefaultObjectACL: toObjectACLRulesFromProto(b.GetDefaultObjectAcl()),

View file

@ -122,7 +122,7 @@ type settings struct {
gax []gax.CallOption
// idempotent indicates if the call is idempotent or not when considering
// if the call should be retired or not.
// if the call should be retried or not.
idempotent bool
// clientOption is a set of option.ClientOption to be used during client
@ -132,6 +132,8 @@ type settings struct {
// userProject is the user project that should be billed for the request.
userProject string
metricsContext *metricsContext
}
func initSettings(opts ...storageOption) *settings {

View file

@ -331,14 +331,14 @@ to add a [custom audit logging] header:
// Use client as usual with the context and the additional headers will be sent.
client.Bucket("my-bucket").Attrs(ctx)
# Experimental gRPC API
# gRPC API
This package includes support for the Cloud Storage gRPC API, which is currently
in preview. This implementation uses gRPC rather than the current JSON & XML
APIs to make requests to Cloud Storage. Kindly contact the Google Cloud Storage gRPC
team at gcs-grpc-contact@google.com with a list of GCS buckets you would like to
allowlist to access this API. The Go Storage gRPC library is not yet generally
available, so it may be subject to breaking changes.
This package includes support for the Cloud Storage gRPC API. The
implementation uses gRPC rather than the Default
JSON & XML APIs to make requests to Cloud Storage.
The Go Storage gRPC client is generally available.
The Notifications, Serivce Account HMAC
and GetServiceAccount RPCs are not supported through the gRPC client.
To create a client which will use gRPC, use the alternate constructor:
@ -349,15 +349,43 @@ To create a client which will use gRPC, use the alternate constructor:
}
// Use client as usual.
If the application is running within GCP, users may get better performance by
enabling Direct Google Access (enabling requests to skip some proxy steps). To enable,
set the environment variable `GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS=true` and add
the following side-effect imports to your application:
Using the gRPC API inside GCP with a bucket in the same region can allow for
[Direct Connectivity] (enabling requests to skip some proxy steps and reducing
response latency). A warning is emmitted if gRPC is not used within GCP to
warn that Direct Connectivity could not be initialized. Direct Connectivity
is not required to access the gRPC API.
import (
_ "google.golang.org/grpc/balancer/rls"
_ "google.golang.org/grpc/xds/googledirectpath"
)
Dependencies for the gRPC API may slightly increase the size of binaries for
applications depending on this package. If you are not using gRPC, you can use
the build tag `disable_grpc_modules` to opt out of these dependencies and
reduce the binary size.
The gRPC client emits metrics by default and will export the
gRPC telemetry discussed in [gRFC/66] and [gRFC/78] to
[Google Cloud Monitoring]. The metrics are accessible through Cloud Monitoring
API and you incur no additional cost for publishing the metrics. Google Cloud
Support can use this information to more quickly diagnose problems related to
GCS and gRPC.
Sending this data does not incur any billing charges, and requires minimal
CPU (a single RPC every minute) or memory (a few KiB to batch the
telemetry).
To access the metrics you can view them through Cloud Monitoring
[metric explorer] with the prefix `storage.googleapis.com/client`. Metrics are emitted
every minute.
You can disable metrics using the following example when creating a new gRPC
client using [WithDisabledClientMetrics].
The metrics exporter uses Cloud Monitoring API which determines
project ID and credentials doing the following:
* Project ID is determined using OTel Resource Detector for the environment
otherwise it falls back to the project provided by [google.FindCredentials].
* Credentials are determined using [Application Default Credentials]. The
principal must have `roles/monitoring.metricWriter` role granted. If not a
logged warning will be emitted. Subsequent are silenced to prevent noisy logs.
# Storage Control API
@ -366,6 +394,11 @@ and Managed Folder operations) are supported via the autogenerated Storage Contr
client, which is available as a subpackage in this module. See package docs at
[cloud.google.com/go/storage/control/apiv2] or reference the [Storage Control API] docs.
[Application Default Credentials]: https://cloud.google.com/docs/authentication/application-default-credentials
[google.FindCredentials]: https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentials
[gRFC/66]: https://github.com/grpc/proposal/blob/master/A66-otel-stats.md
[gRFC/78]: https://github.com/grpc/proposal/blob/master/A78-grpc-metrics-wrr-pf-xds.md
[Google Cloud Monitoring]: https://cloud.google.com/monitoring/docs
[Cloud Storage IAM docs]: https://cloud.google.com/storage/docs/access-control/iam
[XML POST Object docs]: https://cloud.google.com/storage/docs/xml-api/post-object
[Cloud Storage retry docs]: https://cloud.google.com/storage/docs/retry-strategy
@ -375,5 +408,7 @@ client, which is available as a subpackage in this module. See package docs at
[IAM Service Account Credentials API]: https://console.developers.google.com/apis/api/iamcredentials.googleapis.com/overview
[custom audit logging]: https://cloud.google.com/storage/docs/audit-logging#add-custom-metadata
[Storage Control API]: https://cloud.google.com/storage/docs/reference/rpc/google.storage.control.v2
[metric explorer]: https://console.cloud.google.com/projectselector/monitoring/metrics-explorer
[Direct Connectivity]: https://cloud.google.com/vpc-service-controls/docs/set-up-private-connectivity#direct-connectivity
*/
package storage // import "cloud.google.com/go/storage"

154
vendor/cloud.google.com/go/storage/dynamic_delay.go generated vendored Normal file
View file

@ -0,0 +1,154 @@
// 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 storage
import (
"fmt"
"math"
"sync"
"time"
)
// dynamicDelay dynamically calculates the delay at a fixed percentile, based on
// delay samples.
//
// dynamicDelay is goroutine-safe.
type dynamicDelay struct {
increaseFactor float64
decreaseFactor float64
minDelay time.Duration
maxDelay time.Duration
value time.Duration
// Guards the value
mu *sync.RWMutex
}
// NewDynamicDelay returns a dynamicDelay.
//
// targetPercentile is the desired percentile to be computed. For example, a
// targetPercentile of 0.99 computes the delay at the 99th percentile. Must be
// in the range [0, 1].
//
// increaseRate (must be > 0) determines how many increase calls it takes for
// Value to double.
//
// initialDelay is the start value of the delay.
//
// decrease can never lower the delay past minDelay, increase can never raise
// the delay past maxDelay.
func newDynamicDelay(targetPercentile float64, increaseRate float64, initialDelay, minDelay, maxDelay time.Duration) (*dynamicDelay, error) {
if targetPercentile < 0 || targetPercentile > 1 {
return nil, fmt.Errorf("invalid targetPercentile (%v): must be within [0, 1]", targetPercentile)
}
if increaseRate <= 0 {
return nil, fmt.Errorf("invalid increaseRate (%v): must be > 0", increaseRate)
}
if minDelay >= maxDelay {
return nil, fmt.Errorf("invalid minDelay (%v) and maxDelay (%v) combination: minDelay must be smaller than maxDelay", minDelay, maxDelay)
}
if initialDelay < minDelay {
initialDelay = minDelay
}
if initialDelay > maxDelay {
initialDelay = maxDelay
}
// Compute increaseFactor and decreaseFactor such that:
// (increaseFactor ^ (1 - targetPercentile)) * (decreaseFactor ^ targetPercentile) = 1
increaseFactor := math.Exp(math.Log(2) / increaseRate)
if increaseFactor < 1.001 {
increaseFactor = 1.001
}
decreaseFactor := math.Exp(-math.Log(increaseFactor) * (1 - targetPercentile) / targetPercentile)
if decreaseFactor > 0.9999 {
decreaseFactor = 0.9999
}
return &dynamicDelay{
increaseFactor: increaseFactor,
decreaseFactor: decreaseFactor,
minDelay: minDelay,
maxDelay: maxDelay,
value: initialDelay,
mu: &sync.RWMutex{},
}, nil
}
func (d *dynamicDelay) unsafeIncrease() {
v := time.Duration(float64(d.value) * d.increaseFactor)
if v > d.maxDelay {
d.value = d.maxDelay
} else {
d.value = v
}
}
// increase notes that the operation took longer than the delay returned by Value.
func (d *dynamicDelay) increase() {
d.mu.Lock()
defer d.mu.Unlock()
d.unsafeIncrease()
}
func (d *dynamicDelay) unsafeDecrease() {
v := time.Duration(float64(d.value) * d.decreaseFactor)
if v < d.minDelay {
d.value = d.minDelay
} else {
d.value = v
}
}
// decrease notes that the operation completed before the delay returned by getValue.
func (d *dynamicDelay) decrease() {
d.mu.Lock()
defer d.mu.Unlock()
d.unsafeDecrease()
}
// update updates the delay value depending on the specified latency.
func (d *dynamicDelay) update(latency time.Duration) {
d.mu.Lock()
defer d.mu.Unlock()
if latency > d.value {
d.unsafeIncrease()
} else {
d.unsafeDecrease()
}
}
// getValue returns the desired delay to wait before retry the operation.
func (d *dynamicDelay) getValue() time.Duration {
d.mu.RLock()
defer d.mu.RUnlock()
return d.value
}
// PrintDelay prints the state of delay, helpful in debugging.
func (d *dynamicDelay) printDelay() {
d.mu.RLock()
defer d.mu.RUnlock()
fmt.Println("IncreaseFactor: ", d.increaseFactor)
fmt.Println("DecreaseFactor: ", d.decreaseFactor)
fmt.Println("MinDelay: ", d.minDelay)
fmt.Println("MaxDelay: ", d.maxDelay)
fmt.Println("Value: ", d.value)
}

File diff suppressed because it is too large Load diff

22
vendor/cloud.google.com/go/storage/grpc_dp.go generated vendored Normal file
View file

@ -0,0 +1,22 @@
//go:build !disable_grpc_modules
// 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 storage
import (
_ "google.golang.org/grpc/balancer/rls"
_ "google.golang.org/grpc/xds/googledirectpath"
)

275
vendor/cloud.google.com/go/storage/grpc_metrics.go generated vendored Normal file
View file

@ -0,0 +1,275 @@
// 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 storage
import (
"context"
"fmt"
"log"
"strings"
"time"
mexporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric"
"github.com/google/uuid"
"go.opentelemetry.io/contrib/detectors/gcp"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/sdk/metric"
"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/stats/opentelemetry"
)
const (
monitoredResourceName = "storage.googleapis.com/Client"
metricPrefix = "storage.googleapis.com/client/"
)
func latencyHistogramBoundaries() []float64 {
boundaries := []float64{}
boundary := 0.0
increment := 0.002
// 2ms buckets for first 100ms, so we can have higher resolution for uploads and downloads in the 100 KiB range
for i := 0; i < 50; i++ {
boundaries = append(boundaries, boundary)
// increment by 2ms
boundary += increment
}
// For the remaining buckets do 10 10ms, 10 20ms, and so on, up until 5 minutes
for i := 0; i < 150 && boundary < 300; i++ {
boundaries = append(boundaries, boundary)
if i != 0 && i%10 == 0 {
increment *= 2
}
boundary += increment
}
return boundaries
}
func sizeHistogramBoundaries() []float64 {
kb := 1024.0
mb := 1024.0 * kb
gb := 1024.0 * mb
boundaries := []float64{}
boundary := 0.0
increment := 128 * kb
// 128 KiB increments up to 4MiB, then exponential growth
for len(boundaries) < 200 && boundary <= 16*gb {
boundaries = append(boundaries, boundary)
boundary += increment
if boundary >= 4*mb {
increment *= 2
}
}
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,
Kind: metric.InstrumentKindHistogram,
}, metric.Stream{
Name: name,
Aggregation: metric.AggregationExplicitBucketHistogram{Boundaries: boundaries},
})
}
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)
}

View file

@ -20,7 +20,6 @@ import (
"fmt"
"time"
"cloud.google.com/go/storage/internal/apiv2/storagepb"
"google.golang.org/api/iterator"
raw "google.golang.org/api/storage/v1"
)
@ -103,6 +102,7 @@ func (c *Client) HMACKeyHandle(projectID, accessID string) *HMACKeyHandle {
//
// Options such as UserProjectForHMACKeys can be used to set the
// userProject to be billed against for operations.
// Note: gRPC is not supported.
func (hkh *HMACKeyHandle) Get(ctx context.Context, opts ...HMACKeyOption) (*HMACKey, error) {
desc := new(hmacKeyDesc)
for _, opt := range opts {
@ -118,6 +118,7 @@ func (hkh *HMACKeyHandle) Get(ctx context.Context, opts ...HMACKeyOption) (*HMAC
// Delete invokes an RPC to delete the key referenced by accessID, on Google Cloud Storage.
// Only inactive HMAC keys can be deleted.
// After deletion, a key cannot be used to authenticate requests.
// Note: gRPC is not supported.
func (hkh *HMACKeyHandle) Delete(ctx context.Context, opts ...HMACKeyOption) error {
desc := new(hmacKeyDesc)
for _, opt := range opts {
@ -158,23 +159,8 @@ func toHMACKeyFromRaw(hk *raw.HmacKey, updatedTimeCanBeNil bool) (*HMACKey, erro
return hmKey, nil
}
func toHMACKeyFromProto(pbmd *storagepb.HmacKeyMetadata) *HMACKey {
if pbmd == nil {
return nil
}
return &HMACKey{
AccessID: pbmd.GetAccessId(),
ID: pbmd.GetId(),
State: HMACState(pbmd.GetState()),
ProjectID: pbmd.GetProject(),
CreatedTime: convertProtoTime(pbmd.GetCreateTime()),
UpdatedTime: convertProtoTime(pbmd.GetUpdateTime()),
ServiceAccountEmail: pbmd.GetServiceAccountEmail(),
}
}
// CreateHMACKey invokes an RPC for Google Cloud Storage to create a new HMACKey.
// Note: gRPC is not supported.
func (c *Client) CreateHMACKey(ctx context.Context, projectID, serviceAccountEmail string, opts ...HMACKeyOption) (*HMACKey, error) {
if projectID == "" {
return nil, errors.New("storage: expecting a non-blank projectID")
@ -203,6 +189,7 @@ type HMACKeyAttrsToUpdate struct {
}
// Update mutates the HMACKey referred to by accessID.
// Note: gRPC is not supported.
func (h *HMACKeyHandle) Update(ctx context.Context, au HMACKeyAttrsToUpdate, opts ...HMACKeyOption) (*HMACKey, error) {
if au.State != Active && au.State != Inactive {
return nil, fmt.Errorf("storage: invalid state %q for update, must be either %q or %q", au.State, Active, Inactive)
@ -237,6 +224,7 @@ type HMACKeysIterator struct {
// ListHMACKeys returns an iterator for listing HMACKeys.
//
// Note: This iterator is not safe for concurrent operations without explicit synchronization.
// Note: gRPC is not supported.
func (c *Client) ListHMACKeys(ctx context.Context, projectID string, opts ...HMACKeyOption) *HMACKeysIterator {
desc := new(hmacKeyDesc)
for _, opt := range opts {

View file

@ -857,14 +857,7 @@ func (c *httpStorageClient) newRangeReaderXML(ctx context.Context, params *newRa
reopen := readerReopen(ctx, req.Header, params, s,
func(ctx context.Context) (*http.Response, error) {
// Set custom headers passed in via the context. This is only required for XML;
// for gRPC & JSON this is handled in the GAPIC and Apiary layers respectively.
ctxHeaders := callctx.HeadersFromContext(ctx)
for k, vals := range ctxHeaders {
for _, v := range vals {
req.Header.Set(k, v)
}
}
setHeadersFromCtx(ctx, req.Header)
return c.hc.Do(req.WithContext(ctx))
},
func() error { return setConditionsHeaders(req.Header, params.conds) },
@ -1422,18 +1415,20 @@ func parseReadResponse(res *http.Response, params *newRangeReaderParams, reopen
}
} else {
size = res.ContentLength
// Check the CRC iff all of the following hold:
// - We asked for content (length != 0).
// - We got all the content (status != PartialContent).
// - The server sent a CRC header.
// - The Go http stack did not uncompress the file.
// - We were not served compressed data that was uncompressed on download.
// The problem with the last two cases is that the CRC will not match -- GCS
// computes it on the compressed contents, but we compute it on the
// uncompressed contents.
if params.length != 0 && !res.Uncompressed && !uncompressedByServer(res) {
crc, checkCRC = parseCRC32c(res)
}
}
// Check the CRC iff all of the following hold:
// - We asked for content (length != 0).
// - We got all the content (status != PartialContent).
// - The server sent a CRC header.
// - The Go http stack did not uncompress the file.
// - We were not served compressed data that was uncompressed on download.
// The problem with the last two cases is that the CRC will not match -- GCS
// computes it on the compressed contents, but we compute it on the
// uncompressed contents.
crc, checkCRC = parseCRC32c(res)
if params.length == 0 || res.StatusCode == http.StatusPartialContent || res.Uncompressed || uncompressedByServer(res) {
checkCRC = false
}
remain := res.ContentLength
@ -1470,6 +1465,8 @@ func parseReadResponse(res *http.Response, params *newRangeReaderParams, reopen
StartOffset: startOffset,
Generation: params.gen,
Metageneration: metaGen,
CRC32C: crc,
Decompressed: res.Uncompressed || uncompressedByServer(res),
}
return &Reader{
Attrs: attrs,
@ -1484,3 +1481,30 @@ func parseReadResponse(res *http.Response, params *newRangeReaderParams, reopen
},
}, nil
}
// setHeadersFromCtx sets custom headers passed in via the context on the header,
// replacing any header with the same key (which avoids duplicating invocation headers).
// This is only required for XML; for gRPC & JSON requests this is handled in
// the GAPIC and Apiary layers respectively.
func setHeadersFromCtx(ctx context.Context, header http.Header) {
ctxHeaders := callctx.HeadersFromContext(ctx)
for k, vals := range ctxHeaders {
// Merge x-goog-api-client values into a single space-separated value.
if strings.EqualFold(k, xGoogHeaderKey) {
alreadySetValues := header.Values(xGoogHeaderKey)
vals = append(vals, alreadySetValues...)
if len(vals) > 0 {
xGoogHeader := vals[0]
for _, v := range vals[1:] {
xGoogHeader = strings.Join([]string{xGoogHeader, v}, " ")
}
header.Set(k, xGoogHeader)
}
} else {
for _, v := range vals {
header.Set(k, v)
}
}
}
}

View file

@ -0,0 +1,50 @@
// 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
//
// 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.
//go:build go1.23
package storage
import (
"iter"
storagepb "cloud.google.com/go/storage/internal/apiv2/storagepb"
"github.com/googleapis/gax-go/v2/iterator"
)
// All returns an iterator. If an error is returned by the iterator, the
// iterator will stop after that iteration.
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] {
return iterator.RangeAdapter(it.Next)
}

View file

@ -17,19 +17,15 @@
// Package storage is an auto-generated package for the
// Cloud Storage API.
//
// Stop. This folder is likely not what you are looking for. This folder
// contains protocol buffer definitions for an API only accessible to select
// customers. Customers not participating should not depend on this file.
// Please contact Google Cloud sales if you are interested. Unless told
// otherwise by a Google Cloud representative, do not use or otherwise rely
// on any of the contents of this folder. If you would like to use Cloud
// Storage, please consult our official documentation (at
// This folder contains protocol buffer definitions for an API only
// accessible to select customers. Customers not participating should not
// depend on this file. Please contact Google Cloud sales if you are
// interested. Unless told otherwise by a Google Cloud representative, do not
// use or otherwise rely on any of the contents of this folder. If you would
// like to use Cloud Storage, please consult our official documentation (at
// https://cloud.google.com/storage/docs/apis) for details on our XML and
// JSON APIs, or else consider one of our client libraries (at
// https://cloud.google.com/storage/docs/reference/libraries). This API
// defined in this folder is unreleased and may shut off, break, or fail at
// any time for any users who are not registered as a part of a private
// preview program.
// https://cloud.google.com/storage/docs/reference/libraries).
//
// # General documentation
//

View file

@ -50,10 +50,6 @@ type CallOptions struct {
SetIamPolicy []gax.CallOption
TestIamPermissions []gax.CallOption
UpdateBucket []gax.CallOption
DeleteNotificationConfig []gax.CallOption
GetNotificationConfig []gax.CallOption
CreateNotificationConfig []gax.CallOption
ListNotificationConfigs []gax.CallOption
ComposeObject []gax.CallOption
DeleteObject []gax.CallOption
RestoreObject []gax.CallOption
@ -73,6 +69,10 @@ type CallOptions struct {
GetHmacKey []gax.CallOption
ListHmacKeys []gax.CallOption
UpdateHmacKey []gax.CallOption
DeleteNotificationConfig []gax.CallOption
GetNotificationConfig []gax.CallOption
CreateNotificationConfig []gax.CallOption
ListNotificationConfigs []gax.CallOption
}
func defaultGRPCClientOptions() []option.ClientOption {
@ -84,6 +84,7 @@ func defaultGRPCClientOptions() []option.ClientOption {
internaloption.WithDefaultAudience("https://storage.googleapis.com/"),
internaloption.WithDefaultScopes(DefaultAuthScopes()...),
internaloption.EnableJwtWithScope(),
internaloption.EnableNewAuthLibrary(),
option.WithGRPCDialOption(grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(math.MaxInt32))),
}
@ -208,58 +209,6 @@ func defaultCallOptions() *CallOptions {
})
}),
},
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{
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,
})
}),
},
ComposeObject: []gax.CallOption{
gax.WithTimeout(60000 * time.Millisecond),
gax.WithRetry(func() gax.Retryer {
@ -504,6 +453,58 @@ func defaultCallOptions() *CallOptions {
})
}),
},
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{
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,
})
}),
},
}
}
@ -521,10 +522,6 @@ type internalClient interface {
SetIamPolicy(context.Context, *iampb.SetIamPolicyRequest, ...gax.CallOption) (*iampb.Policy, error)
TestIamPermissions(context.Context, *iampb.TestIamPermissionsRequest, ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error)
UpdateBucket(context.Context, *storagepb.UpdateBucketRequest, ...gax.CallOption) (*storagepb.Bucket, 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
ComposeObject(context.Context, *storagepb.ComposeObjectRequest, ...gax.CallOption) (*storagepb.Object, error)
DeleteObject(context.Context, *storagepb.DeleteObjectRequest, ...gax.CallOption) error
RestoreObject(context.Context, *storagepb.RestoreObjectRequest, ...gax.CallOption) (*storagepb.Object, error)
@ -544,6 +541,10 @@ type internalClient interface {
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
}
// Client is a client for interacting with Cloud Storage API.
@ -641,11 +642,13 @@ func (c *Client) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyReques
return c.internalClient.SetIamPolicy(ctx, req, opts...)
}
// TestIamPermissions tests a set of permissions on the given bucket or object to see which, if
// any, are held by the caller.
// TestIamPermissions tests a set of permissions on the given bucket, object, or managed folder
// to see which, if any, are held by the caller.
// The resource field in the request should be
// projects/_/buckets/{bucket} for a bucket or
// projects/_/buckets/{bucket}/objects/{object} for an object.
// projects/_/buckets/{bucket} for a bucket,
// projects/_/buckets/{bucket}/objects/{object} for an object, or
// projects/_/buckets/{bucket}/managedFolders/{managedFolder}
// for a managed folder.
func (c *Client) TestIamPermissions(ctx context.Context, req *iampb.TestIamPermissionsRequest, opts ...gax.CallOption) (*iampb.TestIamPermissionsResponse, error) {
return c.internalClient.TestIamPermissions(ctx, req, opts...)
}
@ -655,29 +658,6 @@ func (c *Client) UpdateBucket(ctx context.Context, req *storagepb.UpdateBucketRe
return c.internalClient.UpdateBucket(ctx, req, opts...)
}
// DeleteNotificationConfig permanently deletes a NotificationConfig.
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.
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).
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.
func (c *Client) ListNotificationConfigs(ctx context.Context, req *storagepb.ListNotificationConfigsRequest, opts ...gax.CallOption) *NotificationConfigIterator {
return c.internalClient.ListNotificationConfigs(ctx, req, opts...)
}
// ComposeObject concatenates a list of existing objects into a new object in the same
// bucket.
func (c *Client) ComposeObject(ctx context.Context, req *storagepb.ComposeObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) {
@ -849,35 +829,78 @@ func (c *Client) QueryWriteStatus(ctx context.Context, req *storagepb.QueryWrite
}
// GetServiceAccount retrieves the name of a projects 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...)
}
// gRPCClient is a client for interacting with Cloud Storage API over gRPC transport.
//
// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls.
@ -1198,6 +1221,9 @@ func (c *gRPCClient) TestIamPermissions(ctx context.Context, req *iampb.TestIamP
if reg := regexp.MustCompile("(?P<bucket>projects/[^/]+/buckets/[^/]+)/objects(?:/.*)?"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 {
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])
}
if reg := regexp.MustCompile("(?P<bucket>projects/[^/]+/buckets/[^/]+)/managedFolders(?:/.*)?"); reg.MatchString(req.GetResource()) && len(url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])) > 0 {
routingHeadersMap["bucket"] = url.QueryEscape(reg.FindStringSubmatch(req.GetResource())[1])
}
for headerName, headerValue := range routingHeadersMap {
routingHeaders = fmt.Sprintf("%s%s=%s&", routingHeaders, headerName, headerValue)
}
@ -1246,138 +1272,6 @@ func (c *gRPCClient) UpdateBucket(ctx context.Context, req *storagepb.UpdateBuck
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
}
func (c *gRPCClient) ComposeObject(ctx context.Context, req *storagepb.ComposeObjectRequest, opts ...gax.CallOption) (*storagepb.Object, error) {
routingHeaders := ""
routingHeadersMap := make(map[string]string)
@ -1917,3 +1811,135 @@ func (c *gRPCClient) UpdateHmacKey(ctx context.Context, req *storagepb.UpdateHma
}
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
}

File diff suppressed because it is too large Load diff

View file

@ -15,4 +15,4 @@
package internal
// Version is the current tagged release of the library.
const Version = "1.43.0"
const Version = "1.44.0"

View file

@ -74,7 +74,15 @@ func run(ctx context.Context, call func(ctx context.Context) error, retry *retry
return true, fmt.Errorf("storage: retry failed after %v attempts; last error: %w", *retry.maxAttempts, err)
}
attempts++
return !errorFunc(err), err
retryable := errorFunc(err)
// Explicitly check context cancellation so that we can distinguish between a
// DEADLINE_EXCEEDED error from the server and a user-set context deadline.
// Unfortunately gRPC will codes.DeadlineExceeded (which may be retryable if it's
// sent by the server) in both cases.
if ctxErr := ctx.Err(); errors.Is(ctxErr, context.Canceled) || errors.Is(ctxErr, context.DeadlineExceeded) {
retryable = false
}
return !retryable, err
})
}
@ -84,21 +92,7 @@ func setInvocationHeaders(ctx context.Context, invocationID string, attempts int
invocationHeader := fmt.Sprintf("gccl-invocation-id/%v gccl-attempt-count/%v", invocationID, attempts)
xGoogHeader := strings.Join([]string{invocationHeader, xGoogDefaultHeader}, " ")
// TODO: remove this once the respective transport packages merge xGoogHeader.
// Also remove gl-go at that time, as it will be repeated.
hdrs := callctx.HeadersFromContext(ctx)
for _, v := range hdrs[xGoogHeaderKey] {
xGoogHeader = strings.Join([]string{xGoogHeader, v}, " ")
}
if hdrs[xGoogHeaderKey] != nil {
// Replace the key instead of adding it, if there was anything to merge with.
hdrs[xGoogHeaderKey] = []string{xGoogHeader}
} else {
// TODO: keep this line when removing the above code.
ctx = callctx.SetHeaders(ctx, xGoogHeaderKey, xGoogHeader)
}
ctx = callctx.SetHeaders(ctx, xGoogHeaderKey, xGoogHeader)
ctx = callctx.SetHeaders(ctx, idempotencyHeaderKey, invocationID)
return ctx
}
@ -138,14 +132,18 @@ func ShouldRetry(err error) bool {
return true
}
}
case *net.DNSError:
if e.IsTemporary {
return true
}
case interface{ Temporary() bool }:
if e.Temporary() {
return true
}
}
// UNAVAILABLE, RESOURCE_EXHAUSTED, and INTERNAL codes are all retryable for gRPC.
// UNAVAILABLE, RESOURCE_EXHAUSTED, INTERNAL, and DEADLINE_EXCEEDED codes are all retryable for gRPC.
if st, ok := status.FromError(err); ok {
if code := st.Code(); code == codes.Unavailable || code == codes.ResourceExhausted || code == codes.Internal {
if code := st.Code(); code == codes.Unavailable || code == codes.ResourceExhausted || code == codes.Internal || code == codes.DeadlineExceeded {
return true
}
}

View file

@ -21,7 +21,6 @@ import (
"regexp"
"cloud.google.com/go/internal/trace"
"cloud.google.com/go/storage/internal/apiv2/storagepb"
raw "google.golang.org/api/storage/v1"
)
@ -92,30 +91,6 @@ func toNotification(rn *raw.Notification) *Notification {
return n
}
func toNotificationFromProto(pbn *storagepb.NotificationConfig) *Notification {
n := &Notification{
ID: pbn.GetName(),
EventTypes: pbn.GetEventTypes(),
ObjectNamePrefix: pbn.GetObjectNamePrefix(),
CustomAttributes: pbn.GetCustomAttributes(),
PayloadFormat: pbn.GetPayloadFormat(),
}
n.TopicProjectID, n.TopicID = parseNotificationTopic(pbn.Topic)
return n
}
func toProtoNotification(n *Notification) *storagepb.NotificationConfig {
return &storagepb.NotificationConfig{
Name: n.ID,
Topic: fmt.Sprintf("//pubsub.googleapis.com/projects/%s/topics/%s",
n.TopicProjectID, n.TopicID),
EventTypes: n.EventTypes,
ObjectNamePrefix: n.ObjectNamePrefix,
CustomAttributes: n.CustomAttributes,
PayloadFormat: n.PayloadFormat,
}
}
var topicRE = regexp.MustCompile(`^//pubsub\.googleapis\.com/projects/([^/]+)/topics/([^/]+)`)
// parseNotificationTopic extracts the project and topic IDs from from the full
@ -144,6 +119,7 @@ func toRawNotification(n *Notification) *raw.Notification {
// AddNotification adds a notification to b. You must set n's TopicProjectID, TopicID
// and PayloadFormat, and must not set its ID. The other fields are all optional. The
// returned Notification's ID can be used to refer to it.
// Note: gRPC is not supported.
func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (ret *Notification, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.AddNotification")
defer func() { trace.EndSpan(ctx, err) }()
@ -165,6 +141,7 @@ func (b *BucketHandle) AddNotification(ctx context.Context, n *Notification) (re
// Notifications returns all the Notifications configured for this bucket, as a map
// indexed by notification ID.
// Note: gRPC is not supported.
func (b *BucketHandle) Notifications(ctx context.Context) (n map[string]*Notification, err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.Notifications")
defer func() { trace.EndSpan(ctx, err) }()
@ -182,15 +159,8 @@ func notificationsToMap(rns []*raw.Notification) map[string]*Notification {
return m
}
func notificationsToMapFromProto(ns []*storagepb.NotificationConfig) map[string]*Notification {
m := map[string]*Notification{}
for _, n := range ns {
m[n.Name] = toNotificationFromProto(n)
}
return m
}
// DeleteNotification deletes the notification with the given ID.
// Note: gRPC is not supported.
func (b *BucketHandle) DeleteNotification(ctx context.Context, id string) (err error) {
ctx = trace.StartSpan(ctx, "cloud.google.com/go/storage.Bucket.DeleteNotification")
defer func() { trace.EndSpan(ctx, err) }()

View file

@ -22,8 +22,9 @@ import (
// storageConfig contains the Storage client option configuration that can be
// set through storageClientOptions.
type storageConfig struct {
useJSONforReads bool
readAPIWasSet bool
useJSONforReads bool
readAPIWasSet bool
disableClientMetrics bool
}
// newStorageConfig generates a new storageConfig with all the given
@ -78,3 +79,32 @@ func (w *withReadAPI) ApplyStorageOpt(c *storageConfig) {
c.useJSONforReads = w.useJSON
c.readAPIWasSet = true
}
type withDisabledClientMetrics struct {
internaloption.EmbeddableAdapter
disabledClientMetrics bool
}
// WithDisabledClientMetrics is an option that may be passed to [NewClient].
// gRPC metrics are enabled by default in the GCS client and will export the
// gRPC telemetry discussed in [gRFC/66] and [gRFC/78] to
// [Google Cloud Monitoring]. The option is used to disable metrics.
// Google Cloud Support can use this information to more quickly diagnose
// problems related to GCS and gRPC.
// Sending this data does not incur any billing charges, and requires minimal
// CPU (a single RPC every few minutes) or memory (a few KiB to batch the
// telemetry).
//
// The default is to enable client metrics. To opt-out of metrics collected use
// this option.
//
// [gRFC/66]: https://github.com/grpc/proposal/blob/master/A66-otel-stats.md
// [gRFC/78]: https://github.com/grpc/proposal/blob/master/A78-grpc-metrics-wrr-pf-xds.md
// [Google Cloud Monitoring]: https://cloud.google.com/monitoring/docs
func WithDisabledClientMetrics() option.ClientOption {
return &withDisabledClientMetrics{disabledClientMetrics: true}
}
func (w *withDisabledClientMetrics) ApplyStorageOpt(c *storageConfig) {
c.disableClientMetrics = w.disabledClientMetrics
}

View file

@ -65,6 +65,19 @@ type ReaderObjectAttrs struct {
// meaningful in the context of a particular generation of a
// particular object.
Metageneration int64
// CRC32C is the CRC32 checksum of the entire object's content using the
// Castagnoli93 polynomial, if available.
CRC32C uint32
// Decompressed is true if the object is stored as a gzip file and was
// decompressed when read.
// Objects are automatically decompressed if the object's metadata property
// "Content-Encoding" is set to "gzip" or satisfies decompressive
// transcoding as per https://cloud.google.com/storage/docs/transcoding.
//
// To prevent decompression on reads, use [ObjectHandle.ReadCompressed].
Decompressed bool
}
// NewReader creates a new Reader to read the contents of the
@ -91,7 +104,8 @@ func (o *ObjectHandle) NewReader(ctx context.Context) (*Reader, error) {
// If the object's metadata property "Content-Encoding" is set to "gzip" or satisfies
// decompressive transcoding per https://cloud.google.com/storage/docs/transcoding
// that file will be served back whole, regardless of the requested range as
// Google Cloud Storage dictates.
// Google Cloud Storage dictates. If decompressive transcoding occurs,
// [Reader.Attrs.Decompressed] will be true.
//
// By default, reads are made using the Cloud Storage XML API. We recommend
// using the JSON API instead, which can be done by setting [WithJSONReads]

View file

@ -1695,7 +1695,6 @@ type Query struct {
// IncludeFoldersAsPrefixes includes Folders and Managed Folders in the set of
// prefixes returned by the query. Only applicable if Delimiter is set to /.
// IncludeFoldersAsPrefixes is not yet implemented in the gRPC API.
IncludeFoldersAsPrefixes bool
// SoftDeleted indicates whether to list soft-deleted objects.
@ -2350,6 +2349,7 @@ func toProtoChecksums(sendCRC32C bool, attrs *ObjectAttrs) *storagepb.ObjectChec
}
// ServiceAccount fetches the email address of the given project's Google Cloud Storage service account.
// Note: gRPC is not supported.
func (c *Client) ServiceAccount(ctx context.Context, projectID string) (string, error) {
o := makeStorageOpts(true, c.retry, "")
return c.tc.GetServiceAccount(ctx, projectID, o...)