From 174b4c070788c7c1eed4ba4bf6d5497198aaf2e6 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Tue, 21 Sep 2021 11:34:34 -0700 Subject: [PATCH] simplify healthcheck implementation (#1555) --- api-bucket-encryption.go | 6 +-- api-bucket-lifecycle.go | 10 ++-- api-bucket-notification.go | 12 ++--- api-bucket-policy.go | 10 ++-- api-bucket-replication.go | 20 ++++---- api-bucket-tagging.go | 6 +-- api-bucket-versioning.go | 8 +-- api-compose-object.go | 8 +-- api-copy-object.go | 2 +- api-get-object-acl.go | 2 +- api-get-object-file.go | 2 +- api-get-object.go | 4 +- api-list.go | 28 +++++------ api-object-legal-hold.go | 4 +- api-object-lock.go | 8 +-- api-object-retention.go | 4 +- api-object-tagging.go | 6 +-- api-presigned.go | 12 ++--- api-put-bucket.go | 6 +-- api-put-object-common.go | 2 +- api-put-object-file-context.go | 2 +- api-put-object-multipart.go | 10 ++-- api-put-object-streaming.go | 10 ++-- api-put-object.go | 6 +-- api-remove.go | 16 +++--- api-restore.go | 2 +- api-select.go | 2 +- api-stat.go | 6 +-- api.go | 91 +++++++++++++++------------------- bucket-cache.go | 6 +-- healthcheck_test.go | 69 ++++++++++++++++++++++++++ retry-continous.go | 2 +- retry.go | 2 +- utils.go | 5 ++ 34 files changed, 227 insertions(+), 162 deletions(-) create mode 100644 healthcheck_test.go diff --git a/api-bucket-encryption.go b/api-bucket-encryption.go index e02ab84af..24f94e034 100644 --- a/api-bucket-encryption.go +++ b/api-bucket-encryption.go @@ -28,7 +28,7 @@ import ( ) // SetBucketEncryption sets the default encryption configuration on an existing bucket. -func (c Client) SetBucketEncryption(ctx context.Context, bucketName string, config *sse.Configuration) error { +func (c *Client) SetBucketEncryption(ctx context.Context, bucketName string, config *sse.Configuration) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -70,7 +70,7 @@ func (c Client) SetBucketEncryption(ctx context.Context, bucketName string, conf } // RemoveBucketEncryption removes the default encryption configuration on a bucket with a context to control cancellations and timeouts. -func (c Client) RemoveBucketEncryption(ctx context.Context, bucketName string) error { +func (c *Client) RemoveBucketEncryption(ctx context.Context, bucketName string) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -99,7 +99,7 @@ func (c Client) RemoveBucketEncryption(ctx context.Context, bucketName string) e // GetBucketEncryption gets the default encryption configuration // on an existing bucket with a context to control cancellations and timeouts. -func (c Client) GetBucketEncryption(ctx context.Context, bucketName string) (*sse.Configuration, error) { +func (c *Client) GetBucketEncryption(ctx context.Context, bucketName string) (*sse.Configuration, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, err diff --git a/api-bucket-lifecycle.go b/api-bucket-lifecycle.go index e1fac813c..7e2199732 100644 --- a/api-bucket-lifecycle.go +++ b/api-bucket-lifecycle.go @@ -30,7 +30,7 @@ import ( ) // SetBucketLifecycle set the lifecycle on an existing bucket. -func (c Client) SetBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error { +func (c *Client) SetBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -51,7 +51,7 @@ func (c Client) SetBucketLifecycle(ctx context.Context, bucketName string, confi } // Saves a new bucket lifecycle. -func (c Client) putBucketLifecycle(ctx context.Context, bucketName string, buf []byte) error { +func (c *Client) putBucketLifecycle(ctx context.Context, bucketName string, buf []byte) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -81,7 +81,7 @@ func (c Client) putBucketLifecycle(ctx context.Context, bucketName string, buf [ } // Remove lifecycle from a bucket. -func (c Client) removeBucketLifecycle(ctx context.Context, bucketName string) error { +func (c *Client) removeBucketLifecycle(ctx context.Context, bucketName string) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -101,7 +101,7 @@ func (c Client) removeBucketLifecycle(ctx context.Context, bucketName string) er } // GetBucketLifecycle fetch bucket lifecycle configuration -func (c Client) GetBucketLifecycle(ctx context.Context, bucketName string) (*lifecycle.Configuration, error) { +func (c *Client) GetBucketLifecycle(ctx context.Context, bucketName string) (*lifecycle.Configuration, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, err @@ -120,7 +120,7 @@ func (c Client) GetBucketLifecycle(ctx context.Context, bucketName string) (*lif } // Request server for current bucket lifecycle. -func (c Client) getBucketLifecycle(ctx context.Context, bucketName string) ([]byte, error) { +func (c *Client) getBucketLifecycle(ctx context.Context, bucketName string) ([]byte, error) { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) diff --git a/api-bucket-notification.go b/api-bucket-notification.go index 76787ecab..1e6f3da1c 100644 --- a/api-bucket-notification.go +++ b/api-bucket-notification.go @@ -32,7 +32,7 @@ import ( ) // SetBucketNotification saves a new bucket notification with a context to control cancellations and timeouts. -func (c Client) SetBucketNotification(ctx context.Context, bucketName string, config notification.Configuration) error { +func (c *Client) SetBucketNotification(ctx context.Context, bucketName string, config notification.Configuration) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -73,12 +73,12 @@ func (c Client) SetBucketNotification(ctx context.Context, bucketName string, co } // RemoveAllBucketNotification - Remove bucket notification clears all previously specified config -func (c Client) RemoveAllBucketNotification(ctx context.Context, bucketName string) error { +func (c *Client) RemoveAllBucketNotification(ctx context.Context, bucketName string) error { return c.SetBucketNotification(ctx, bucketName, notification.Configuration{}) } // GetBucketNotification returns current bucket notification configuration -func (c Client) GetBucketNotification(ctx context.Context, bucketName string) (bucketNotification notification.Configuration, err error) { +func (c *Client) GetBucketNotification(ctx context.Context, bucketName string) (bucketNotification notification.Configuration, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return notification.Configuration{}, err @@ -87,7 +87,7 @@ func (c Client) GetBucketNotification(ctx context.Context, bucketName string) (b } // Request server for notification rules. -func (c Client) getBucketNotification(ctx context.Context, bucketName string) (notification.Configuration, error) { +func (c *Client) getBucketNotification(ctx context.Context, bucketName string) (notification.Configuration, error) { urlValues := make(url.Values) urlValues.Set("notification", "") @@ -121,12 +121,12 @@ func processBucketNotificationResponse(bucketName string, resp *http.Response) ( } // ListenNotification listen for all events, this is a MinIO specific API -func (c Client) ListenNotification(ctx context.Context, prefix, suffix string, events []string) <-chan notification.Info { +func (c *Client) ListenNotification(ctx context.Context, prefix, suffix string, events []string) <-chan notification.Info { return c.ListenBucketNotification(ctx, "", prefix, suffix, events) } // ListenBucketNotification listen for bucket events, this is a MinIO specific API -func (c Client) ListenBucketNotification(ctx context.Context, bucketName, prefix, suffix string, events []string) <-chan notification.Info { +func (c *Client) ListenBucketNotification(ctx context.Context, bucketName, prefix, suffix string, events []string) <-chan notification.Info { notificationInfoCh := make(chan notification.Info, 1) const notificationCapacity = 4 * 1024 * 1024 notificationEventBuffer := make([]byte, notificationCapacity) diff --git a/api-bucket-policy.go b/api-bucket-policy.go index 7e01275df..57cdbc6e3 100644 --- a/api-bucket-policy.go +++ b/api-bucket-policy.go @@ -27,7 +27,7 @@ import ( ) // SetBucketPolicy sets the access permissions on an existing bucket. -func (c Client) SetBucketPolicy(ctx context.Context, bucketName, policy string) error { +func (c *Client) SetBucketPolicy(ctx context.Context, bucketName, policy string) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -43,7 +43,7 @@ func (c Client) SetBucketPolicy(ctx context.Context, bucketName, policy string) } // Saves a new bucket policy. -func (c Client) putBucketPolicy(ctx context.Context, bucketName, policy string) error { +func (c *Client) putBucketPolicy(ctx context.Context, bucketName, policy string) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -71,7 +71,7 @@ func (c Client) putBucketPolicy(ctx context.Context, bucketName, policy string) } // Removes all policies on a bucket. -func (c Client) removeBucketPolicy(ctx context.Context, bucketName string) error { +func (c *Client) removeBucketPolicy(ctx context.Context, bucketName string) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -91,7 +91,7 @@ func (c Client) removeBucketPolicy(ctx context.Context, bucketName string) error } // GetBucketPolicy returns the current policy -func (c Client) GetBucketPolicy(ctx context.Context, bucketName string) (string, error) { +func (c *Client) GetBucketPolicy(ctx context.Context, bucketName string) (string, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return "", err @@ -108,7 +108,7 @@ func (c Client) GetBucketPolicy(ctx context.Context, bucketName string) (string, } // Request server for current bucket policy. -func (c Client) getBucketPolicy(ctx context.Context, bucketName string) (string, error) { +func (c *Client) getBucketPolicy(ctx context.Context, bucketName string) (string, error) { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) diff --git a/api-bucket-replication.go b/api-bucket-replication.go index 0b357d3e2..4c4d21f59 100644 --- a/api-bucket-replication.go +++ b/api-bucket-replication.go @@ -33,12 +33,12 @@ import ( ) // RemoveBucketReplication removes a replication config on an existing bucket. -func (c Client) RemoveBucketReplication(ctx context.Context, bucketName string) error { +func (c *Client) RemoveBucketReplication(ctx context.Context, bucketName string) error { return c.removeBucketReplication(ctx, bucketName) } // SetBucketReplication sets a replication config on an existing bucket. -func (c Client) SetBucketReplication(ctx context.Context, bucketName string, cfg replication.Config) error { +func (c *Client) SetBucketReplication(ctx context.Context, bucketName string, cfg replication.Config) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -53,7 +53,7 @@ func (c Client) SetBucketReplication(ctx context.Context, bucketName string, cfg } // Saves a new bucket replication. -func (c Client) putBucketReplication(ctx context.Context, bucketName string, cfg replication.Config) error { +func (c *Client) putBucketReplication(ctx context.Context, bucketName string, cfg replication.Config) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -86,7 +86,7 @@ func (c Client) putBucketReplication(ctx context.Context, bucketName string, cfg } // Remove replication from a bucket. -func (c Client) removeBucketReplication(ctx context.Context, bucketName string) error { +func (c *Client) removeBucketReplication(ctx context.Context, bucketName string) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -107,7 +107,7 @@ func (c Client) removeBucketReplication(ctx context.Context, bucketName string) // GetBucketReplication fetches bucket replication configuration.If config is not // found, returns empty config with nil error. -func (c Client) GetBucketReplication(ctx context.Context, bucketName string) (cfg replication.Config, err error) { +func (c *Client) GetBucketReplication(ctx context.Context, bucketName string) (cfg replication.Config, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return cfg, err @@ -124,7 +124,7 @@ func (c Client) GetBucketReplication(ctx context.Context, bucketName string) (cf } // Request server for current bucket replication config. -func (c Client) getBucketReplication(ctx context.Context, bucketName string) (cfg replication.Config, err error) { +func (c *Client) getBucketReplication(ctx context.Context, bucketName string) (cfg replication.Config, err error) { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -153,7 +153,7 @@ func (c Client) getBucketReplication(ctx context.Context, bucketName string) (cf } // GetBucketReplicationMetrics fetches bucket replication status metrics -func (c Client) GetBucketReplicationMetrics(ctx context.Context, bucketName string) (s replication.Metrics, err error) { +func (c *Client) GetBucketReplicationMetrics(ctx context.Context, bucketName string) (s replication.Metrics, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return s, err @@ -199,7 +199,7 @@ func mustGetUUID() string { // ResetBucketReplication kicks off replication of previously replicated objects if ExistingObjectReplication // is enabled in the replication config -func (c Client) ResetBucketReplication(ctx context.Context, bucketName string, olderThan time.Duration) (rID string, err error) { +func (c *Client) ResetBucketReplication(ctx context.Context, bucketName string, olderThan time.Duration) (rID string, err error) { rID = mustGetUUID() _, err = c.resetBucketReplicationOnTarget(ctx, bucketName, olderThan, "", rID) if err != nil { @@ -210,14 +210,14 @@ func (c Client) ResetBucketReplication(ctx context.Context, bucketName string, o // ResetBucketReplication kicks off replication of previously replicated objects if ExistingObjectReplication // is enabled in the replication config -func (c Client) ResetBucketReplicationOnTarget(ctx context.Context, bucketName string, olderThan time.Duration, tgtArn string) (rinfo replication.ResyncTargetsInfo, err error) { +func (c *Client) ResetBucketReplicationOnTarget(ctx context.Context, bucketName string, olderThan time.Duration, tgtArn string) (rinfo replication.ResyncTargetsInfo, err error) { rID := mustGetUUID() return c.resetBucketReplicationOnTarget(ctx, bucketName, olderThan, tgtArn, rID) } // ResetBucketReplication kicks off replication of previously replicated objects if ExistingObjectReplication // is enabled in the replication config -func (c Client) resetBucketReplicationOnTarget(ctx context.Context, bucketName string, olderThan time.Duration, tgtArn string, resetID string) (rinfo replication.ResyncTargetsInfo, err error) { +func (c *Client) resetBucketReplicationOnTarget(ctx context.Context, bucketName string, olderThan time.Duration, tgtArn string, resetID string) (rinfo replication.ResyncTargetsInfo, err error) { // Input validation. if err = s3utils.CheckValidBucketName(bucketName); err != nil { return diff --git a/api-bucket-tagging.go b/api-bucket-tagging.go index fcb966e63..1615f8f87 100644 --- a/api-bucket-tagging.go +++ b/api-bucket-tagging.go @@ -32,7 +32,7 @@ import ( // GetBucketTagging fetch tagging configuration for a bucket with a // context to control cancellations and timeouts. -func (c Client) GetBucketTagging(ctx context.Context, bucketName string) (*tags.Tags, error) { +func (c *Client) GetBucketTagging(ctx context.Context, bucketName string) (*tags.Tags, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, err @@ -64,7 +64,7 @@ func (c Client) GetBucketTagging(ctx context.Context, bucketName string) (*tags. // SetBucketTagging sets tagging configuration for a bucket // with a context to control cancellations and timeouts. -func (c Client) SetBucketTagging(ctx context.Context, bucketName string, tags *tags.Tags) error { +func (c *Client) SetBucketTagging(ctx context.Context, bucketName string, tags *tags.Tags) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -107,7 +107,7 @@ func (c Client) SetBucketTagging(ctx context.Context, bucketName string, tags *t // RemoveBucketTagging removes tagging configuration for a // bucket with a context to control cancellations and timeouts. -func (c Client) RemoveBucketTagging(ctx context.Context, bucketName string) error { +func (c *Client) RemoveBucketTagging(ctx context.Context, bucketName string) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err diff --git a/api-bucket-versioning.go b/api-bucket-versioning.go index e3ceeb336..930b1b93a 100644 --- a/api-bucket-versioning.go +++ b/api-bucket-versioning.go @@ -27,7 +27,7 @@ import ( ) // SetBucketVersioning sets a bucket versioning configuration -func (c Client) SetBucketVersioning(ctx context.Context, bucketName string, config BucketVersioningConfiguration) error { +func (c *Client) SetBucketVersioning(ctx context.Context, bucketName string, config BucketVersioningConfiguration) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -67,12 +67,12 @@ func (c Client) SetBucketVersioning(ctx context.Context, bucketName string, conf } // EnableVersioning - enable object versioning in given bucket. -func (c Client) EnableVersioning(ctx context.Context, bucketName string) error { +func (c *Client) EnableVersioning(ctx context.Context, bucketName string) error { return c.SetBucketVersioning(ctx, bucketName, BucketVersioningConfiguration{Status: "Enabled"}) } // SuspendVersioning - suspend object versioning in given bucket. -func (c Client) SuspendVersioning(ctx context.Context, bucketName string) error { +func (c *Client) SuspendVersioning(ctx context.Context, bucketName string) error { return c.SetBucketVersioning(ctx, bucketName, BucketVersioningConfiguration{Status: "Suspended"}) } @@ -102,7 +102,7 @@ func (b BucketVersioningConfiguration) Suspended() bool { // GetBucketVersioning gets the versioning configuration on // an existing bucket with a context to control cancellations and timeouts. -func (c Client) GetBucketVersioning(ctx context.Context, bucketName string) (BucketVersioningConfiguration, error) { +func (c *Client) GetBucketVersioning(ctx context.Context, bucketName string) (BucketVersioningConfiguration, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return BucketVersioningConfiguration{}, err diff --git a/api-compose-object.go b/api-compose-object.go index 19a72ac39..cbbb5509a 100644 --- a/api-compose-object.go +++ b/api-compose-object.go @@ -201,7 +201,7 @@ func (opts CopySrcOptions) validate() (err error) { } // Low level implementation of CopyObject API, supports only upto 5GiB worth of copy. -func (c Client) copyObjectDo(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, +func (c *Client) copyObjectDo(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, metadata map[string]string, srcOpts CopySrcOptions, dstOpts PutObjectOptions) (ObjectInfo, error) { // Build headers. @@ -282,7 +282,7 @@ func (c Client) copyObjectDo(ctx context.Context, srcBucket, srcObject, destBuck return objInfo, nil } -func (c Client) copyObjectPartDo(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, uploadID string, +func (c *Client) copyObjectPartDo(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, uploadID string, partID int, startOffset int64, length int64, metadata map[string]string) (p CompletePart, err error) { headers := make(http.Header) @@ -335,7 +335,7 @@ func (c Client) copyObjectPartDo(ctx context.Context, srcBucket, srcObject, dest // uploadPartCopy - helper function to create a part in a multipart // upload via an upload-part-copy request // https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html -func (c Client) uploadPartCopy(ctx context.Context, bucket, object, uploadID string, partNumber int, +func (c *Client) uploadPartCopy(ctx context.Context, bucket, object, uploadID string, partNumber int, headers http.Header) (p CompletePart, err error) { // Build query parameters @@ -375,7 +375,7 @@ func (c Client) uploadPartCopy(ctx context.Context, bucket, object, uploadID str // and concatenates them into a new object using only server-side copying // operations. Optionally takes progress reader hook for applications to // look at current progress. -func (c Client) ComposeObject(ctx context.Context, dst CopyDestOptions, srcs ...CopySrcOptions) (UploadInfo, error) { +func (c *Client) ComposeObject(ctx context.Context, dst CopyDestOptions, srcs ...CopySrcOptions) (UploadInfo, error) { if len(srcs) < 1 || len(srcs) > maxPartsCount { return UploadInfo{}, errInvalidArgument("There must be as least one and up to 10000 source objects.") } diff --git a/api-copy-object.go b/api-copy-object.go index 9af036ec0..1c0ad2be4 100644 --- a/api-copy-object.go +++ b/api-copy-object.go @@ -25,7 +25,7 @@ import ( ) // CopyObject - copy a source object into a new object -func (c Client) CopyObject(ctx context.Context, dst CopyDestOptions, src CopySrcOptions) (UploadInfo, error) { +func (c *Client) CopyObject(ctx context.Context, dst CopyDestOptions, src CopySrcOptions) (UploadInfo, error) { if err := src.validate(); err != nil { return UploadInfo{}, err } diff --git a/api-get-object-acl.go b/api-get-object-acl.go index 031aa32e1..6b313e733 100644 --- a/api-get-object-acl.go +++ b/api-get-object-acl.go @@ -52,7 +52,7 @@ type accessControlPolicy struct { } // GetObjectACL get object ACLs -func (c Client) GetObjectACL(ctx context.Context, bucketName, objectName string) (*ObjectInfo, error) { +func (c *Client) GetObjectACL(ctx context.Context, bucketName, objectName string) (*ObjectInfo, error) { resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{ bucketName: bucketName, objectName: objectName, diff --git a/api-get-object-file.go b/api-get-object-file.go index bccff4578..98f5acf6e 100644 --- a/api-get-object-file.go +++ b/api-get-object-file.go @@ -28,7 +28,7 @@ import ( // FGetObject - download contents of an object to a local file. // The options can be used to specify the GET request further. -func (c Client) FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error { +func (c *Client) FGetObject(ctx context.Context, bucketName, objectName, filePath string, opts GetObjectOptions) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err diff --git a/api-get-object.go b/api-get-object.go index ef9dd45d4..4fdbc9960 100644 --- a/api-get-object.go +++ b/api-get-object.go @@ -30,7 +30,7 @@ import ( ) // GetObject wrapper function that accepts a request context -func (c Client) GetObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error) { +func (c *Client) GetObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (*Object, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, err @@ -639,7 +639,7 @@ func newObject(reqCh chan<- getRequest, resCh <-chan getResponse, doneCh chan<- // // For more information about the HTTP Range header. // go to http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35. -func (c Client) getObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (io.ReadCloser, ObjectInfo, http.Header, error) { +func (c *Client) getObject(ctx context.Context, bucketName, objectName string, opts GetObjectOptions) (io.ReadCloser, ObjectInfo, http.Header, error) { // Validate input arguments. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, ObjectInfo{}, nil, err diff --git a/api-list.go b/api-list.go index 431bae540..a8d7e7137 100644 --- a/api-list.go +++ b/api-list.go @@ -36,7 +36,7 @@ import ( // fmt.Println(message) // } // -func (c Client) ListBuckets(ctx context.Context) ([]BucketInfo, error) { +func (c *Client) ListBuckets(ctx context.Context) ([]BucketInfo, error) { // Execute GET on service. resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{contentSHA256Hex: emptySHA256Hex}) defer closeResponse(resp) @@ -57,7 +57,7 @@ func (c Client) ListBuckets(ctx context.Context) ([]BucketInfo, error) { } /// Bucket List Operations. -func (c Client) listObjectsV2(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { +func (c *Client) listObjectsV2(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { // Allocate new list objects channel. objectStatCh := make(chan ObjectInfo, 1) // Default listing is delimited at "/" @@ -153,7 +153,7 @@ func (c Client) listObjectsV2(ctx context.Context, bucketName string, opts ListO // ?delimiter - A delimiter is a character you use to group keys. // ?start-after - Sets a marker to start listing lexically at this key onwards. // ?max-keys - Sets the maximum number of keys returned in the response body. -func (c Client) listObjectsV2Query(ctx context.Context, bucketName, objectPrefix, continuationToken string, fetchOwner, metadata bool, delimiter string, startAfter string, maxkeys int, headers http.Header) (ListBucketV2Result, error) { +func (c *Client) listObjectsV2Query(ctx context.Context, bucketName, objectPrefix, continuationToken string, fetchOwner, metadata bool, delimiter string, startAfter string, maxkeys int, headers http.Header) (ListBucketV2Result, error) { // Validate bucket name. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return ListBucketV2Result{}, err @@ -252,7 +252,7 @@ func (c Client) listObjectsV2Query(ctx context.Context, bucketName, objectPrefix return listBucketResult, nil } -func (c Client) listObjects(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { +func (c *Client) listObjects(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { // Allocate new list objects channel. objectStatCh := make(chan ObjectInfo, 1) // Default listing is delimited at "/" @@ -332,7 +332,7 @@ func (c Client) listObjects(ctx context.Context, bucketName string, opts ListObj return objectStatCh } -func (c Client) listObjectVersions(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { +func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { // Allocate new list objects channel. resultCh := make(chan ObjectInfo, 1) // Default listing is delimited at "/" @@ -443,7 +443,7 @@ func (c Client) listObjectVersions(ctx context.Context, bucketName string, opts // ?delimiter - A delimiter is a character you use to group keys. // ?prefix - Limits the response to keys that begin with the specified prefix. // ?max-keys - Sets the maximum number of keys returned in the response body. -func (c Client) listObjectVersionsQuery(ctx context.Context, bucketName, prefix, keyMarker, versionIDMarker, delimiter string, maxkeys int, headers http.Header) (ListVersionsResult, error) { +func (c *Client) listObjectVersionsQuery(ctx context.Context, bucketName, prefix, keyMarker, versionIDMarker, delimiter string, maxkeys int, headers http.Header) (ListVersionsResult, error) { // Validate bucket name. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return ListVersionsResult{}, err @@ -540,7 +540,7 @@ func (c Client) listObjectVersionsQuery(ctx context.Context, bucketName, prefix, // ?delimiter - A delimiter is a character you use to group keys. // ?prefix - Limits the response to keys that begin with the specified prefix. // ?max-keys - Sets the maximum number of keys returned in the response body. -func (c Client) listObjectsQuery(ctx context.Context, bucketName, objectPrefix, objectMarker, delimiter string, maxkeys int, headers http.Header) (ListBucketResult, error) { +func (c *Client) listObjectsQuery(ctx context.Context, bucketName, objectPrefix, objectMarker, delimiter string, maxkeys int, headers http.Header) (ListBucketResult, error) { // Validate bucket name. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return ListBucketResult{}, err @@ -661,7 +661,7 @@ func (o *ListObjectsOptions) Set(key, value string) { // fmt.Println(object) // } // -func (c Client) ListObjects(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { +func (c *Client) ListObjects(ctx context.Context, bucketName string, opts ListObjectsOptions) <-chan ObjectInfo { if opts.WithVersions { return c.listObjectVersions(ctx, bucketName, opts) } @@ -697,12 +697,12 @@ func (c Client) ListObjects(ctx context.Context, bucketName string, opts ListObj // for message := range api.ListIncompleteUploads(context.Background(), "mytestbucket", "starthere", recursive) { // fmt.Println(message) // } -func (c Client) ListIncompleteUploads(ctx context.Context, bucketName, objectPrefix string, recursive bool) <-chan ObjectMultipartInfo { +func (c *Client) ListIncompleteUploads(ctx context.Context, bucketName, objectPrefix string, recursive bool) <-chan ObjectMultipartInfo { return c.listIncompleteUploads(ctx, bucketName, objectPrefix, recursive) } // listIncompleteUploads lists all incomplete uploads. -func (c Client) listIncompleteUploads(ctx context.Context, bucketName, objectPrefix string, recursive bool) <-chan ObjectMultipartInfo { +func (c *Client) listIncompleteUploads(ctx context.Context, bucketName, objectPrefix string, recursive bool) <-chan ObjectMultipartInfo { // Allocate channel for multipart uploads. objectMultipartStatCh := make(chan ObjectMultipartInfo, 1) // Delimiter is set to "/" by default. @@ -788,7 +788,7 @@ func (c Client) listIncompleteUploads(ctx context.Context, bucketName, objectPre // ?delimiter - A delimiter is a character you use to group keys. // ?prefix - Limits the response to keys that begin with the specified prefix. // ?max-uploads - Sets the maximum number of multipart uploads returned in the response body. -func (c Client) listMultipartUploadsQuery(ctx context.Context, bucketName, keyMarker, uploadIDMarker, prefix, delimiter string, maxUploads int) (ListMultipartUploadsResult, error) { +func (c *Client) listMultipartUploadsQuery(ctx context.Context, bucketName, keyMarker, uploadIDMarker, prefix, delimiter string, maxUploads int) (ListMultipartUploadsResult, error) { // Get resources properly escaped and lined up before using them in http request. urlValues := make(url.Values) // Set uploads. @@ -867,7 +867,7 @@ func (c Client) listMultipartUploadsQuery(ctx context.Context, bucketName, keyMa } // listObjectParts list all object parts recursively. -func (c Client) listObjectParts(ctx context.Context, bucketName, objectName, uploadID string) (partsInfo map[int]ObjectPart, err error) { +func (c *Client) listObjectParts(ctx context.Context, bucketName, objectName, uploadID string) (partsInfo map[int]ObjectPart, err error) { // Part number marker for the next batch of request. var nextPartNumberMarker int partsInfo = make(map[int]ObjectPart) @@ -896,7 +896,7 @@ func (c Client) listObjectParts(ctx context.Context, bucketName, objectName, upl } // findUploadIDs lists all incomplete uploads and find the uploadIDs of the matching object name. -func (c Client) findUploadIDs(ctx context.Context, bucketName, objectName string) ([]string, error) { +func (c *Client) findUploadIDs(ctx context.Context, bucketName, objectName string) ([]string, error) { var uploadIDs []string // Make list incomplete uploads recursive. isRecursive := true @@ -923,7 +923,7 @@ func (c Client) findUploadIDs(ctx context.Context, bucketName, objectName string // ?part-number-marker - Specifies the part after which listing should // begin. // ?max-parts - Maximum parts to be listed per request. -func (c Client) listObjectPartsQuery(ctx context.Context, bucketName, objectName, uploadID string, partNumberMarker, maxParts int) (ListObjectPartsResult, error) { +func (c *Client) listObjectPartsQuery(ctx context.Context, bucketName, objectName, uploadID string, partNumberMarker, maxParts int) (ListObjectPartsResult, error) { // Get resources properly escaped and lined up before using them in http request. urlValues := make(url.Values) // Set part number marker. diff --git a/api-object-legal-hold.go b/api-object-legal-hold.go index b139c1687..0c027d550 100644 --- a/api-object-legal-hold.go +++ b/api-object-legal-hold.go @@ -81,7 +81,7 @@ func newObjectLegalHold(status *LegalHoldStatus) (*objectLegalHold, error) { } // PutObjectLegalHold : sets object legal hold for a given object and versionID. -func (c Client) PutObjectLegalHold(ctx context.Context, bucketName, objectName string, opts PutObjectLegalHoldOptions) error { +func (c *Client) PutObjectLegalHold(ctx context.Context, bucketName, objectName string, opts PutObjectLegalHoldOptions) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -135,7 +135,7 @@ func (c Client) PutObjectLegalHold(ctx context.Context, bucketName, objectName s } // GetObjectLegalHold gets legal-hold status of given object. -func (c Client) GetObjectLegalHold(ctx context.Context, bucketName, objectName string, opts GetObjectLegalHoldOptions) (status *LegalHoldStatus, err error) { +func (c *Client) GetObjectLegalHold(ctx context.Context, bucketName, objectName string, opts GetObjectLegalHoldOptions) (status *LegalHoldStatus, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, err diff --git a/api-object-lock.go b/api-object-lock.go index 29f52b054..f0a439853 100644 --- a/api-object-lock.go +++ b/api-object-lock.go @@ -139,7 +139,7 @@ func newObjectLockConfig(mode *RetentionMode, validity *uint, unit *ValidityUnit } // SetBucketObjectLockConfig sets object lock configuration in given bucket. mode, validity and unit are either all set or all nil. -func (c Client) SetBucketObjectLockConfig(ctx context.Context, bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error { +func (c *Client) SetBucketObjectLockConfig(ctx context.Context, bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -184,7 +184,7 @@ func (c Client) SetBucketObjectLockConfig(ctx context.Context, bucketName string } // GetObjectLockConfig gets object lock configuration of given bucket. -func (c Client) GetObjectLockConfig(ctx context.Context, bucketName string) (objectLock string, mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) { +func (c *Client) GetObjectLockConfig(ctx context.Context, bucketName string) (objectLock string, mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return "", nil, nil, nil, err @@ -230,12 +230,12 @@ func (c Client) GetObjectLockConfig(ctx context.Context, bucketName string) (obj } // GetBucketObjectLockConfig gets object lock configuration of given bucket. -func (c Client) GetBucketObjectLockConfig(ctx context.Context, bucketName string) (mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) { +func (c *Client) GetBucketObjectLockConfig(ctx context.Context, bucketName string) (mode *RetentionMode, validity *uint, unit *ValidityUnit, err error) { _, mode, validity, unit, err = c.GetObjectLockConfig(ctx, bucketName) return mode, validity, unit, err } // SetObjectLockConfig sets object lock configuration in given bucket. mode, validity and unit are either all set or all nil. -func (c Client) SetObjectLockConfig(ctx context.Context, bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error { +func (c *Client) SetObjectLockConfig(ctx context.Context, bucketName string, mode *RetentionMode, validity *uint, unit *ValidityUnit) error { return c.SetBucketObjectLockConfig(ctx, bucketName, mode, validity, unit) } diff --git a/api-object-retention.go b/api-object-retention.go index 54f2762de..b29cb1f8d 100644 --- a/api-object-retention.go +++ b/api-object-retention.go @@ -63,7 +63,7 @@ type PutObjectRetentionOptions struct { } // PutObjectRetention sets object retention for a given object and versionID. -func (c Client) PutObjectRetention(ctx context.Context, bucketName, objectName string, opts PutObjectRetentionOptions) error { +func (c *Client) PutObjectRetention(ctx context.Context, bucketName, objectName string, opts PutObjectRetentionOptions) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -126,7 +126,7 @@ func (c Client) PutObjectRetention(ctx context.Context, bucketName, objectName s } // GetObjectRetention gets retention of given object. -func (c Client) GetObjectRetention(ctx context.Context, bucketName, objectName, versionID string) (mode *RetentionMode, retainUntilDate *time.Time, err error) { +func (c *Client) GetObjectRetention(ctx context.Context, bucketName, objectName, versionID string) (mode *RetentionMode, retainUntilDate *time.Time, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, nil, err diff --git a/api-object-tagging.go b/api-object-tagging.go index 2709efcd1..305c36de8 100644 --- a/api-object-tagging.go +++ b/api-object-tagging.go @@ -36,7 +36,7 @@ type PutObjectTaggingOptions struct { // PutObjectTagging replaces or creates object tag(s) and can target // a specific object version in a versioned bucket. -func (c Client) PutObjectTagging(ctx context.Context, bucketName, objectName string, otags *tags.Tags, opts PutObjectTaggingOptions) error { +func (c *Client) PutObjectTagging(ctx context.Context, bucketName, objectName string, otags *tags.Tags, opts PutObjectTaggingOptions) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -87,7 +87,7 @@ type GetObjectTaggingOptions struct { // GetObjectTagging fetches object tag(s) with options to target // a specific object version in a versioned bucket. -func (c Client) GetObjectTagging(ctx context.Context, bucketName, objectName string, opts GetObjectTaggingOptions) (*tags.Tags, error) { +func (c *Client) GetObjectTagging(ctx context.Context, bucketName, objectName string, opts GetObjectTaggingOptions) (*tags.Tags, error) { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) @@ -125,7 +125,7 @@ type RemoveObjectTaggingOptions struct { // RemoveObjectTagging removes object tag(s) with options to control a specific object // version in a versioned bucket -func (c Client) RemoveObjectTagging(ctx context.Context, bucketName, objectName string, opts RemoveObjectTaggingOptions) error { +func (c *Client) RemoveObjectTagging(ctx context.Context, bucketName, objectName string, opts RemoveObjectTaggingOptions) error { // Get resources properly escaped and lined up before // using them in http request. urlValues := make(url.Values) diff --git a/api-presigned.go b/api-presigned.go index 80c363da5..10977a34f 100644 --- a/api-presigned.go +++ b/api-presigned.go @@ -30,7 +30,7 @@ import ( // presignURL - Returns a presigned URL for an input 'method'. // Expires maximum is 7days - ie. 604800 and minimum is 1. -func (c Client) presignURL(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { +func (c *Client) presignURL(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { // Input validation. if method == "" { return nil, errInvalidArgument("method cannot be empty.") @@ -65,7 +65,7 @@ func (c Client) presignURL(ctx context.Context, method string, bucketName string // data without credentials. URL can have a maximum expiry of // upto 7days or a minimum of 1sec. Additionally you can override // a set of response headers using the query parameters. -func (c Client) PresignedGetObject(ctx context.Context, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { +func (c *Client) PresignedGetObject(ctx context.Context, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { if err = s3utils.CheckValidObjectName(objectName); err != nil { return nil, err } @@ -76,7 +76,7 @@ func (c Client) PresignedGetObject(ctx context.Context, bucketName string, objec // object metadata without credentials. URL can have a maximum expiry // of upto 7days or a minimum of 1sec. Additionally you can override // a set of response headers using the query parameters. -func (c Client) PresignedHeadObject(ctx context.Context, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { +func (c *Client) PresignedHeadObject(ctx context.Context, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { if err = s3utils.CheckValidObjectName(objectName); err != nil { return nil, err } @@ -86,7 +86,7 @@ func (c Client) PresignedHeadObject(ctx context.Context, bucketName string, obje // PresignedPutObject - Returns a presigned URL to upload an object // without credentials. URL can have a maximum expiry of upto 7days // or a minimum of 1sec. -func (c Client) PresignedPutObject(ctx context.Context, bucketName string, objectName string, expires time.Duration) (u *url.URL, err error) { +func (c *Client) PresignedPutObject(ctx context.Context, bucketName string, objectName string, expires time.Duration) (u *url.URL, err error) { if err = s3utils.CheckValidObjectName(objectName); err != nil { return nil, err } @@ -96,12 +96,12 @@ func (c Client) PresignedPutObject(ctx context.Context, bucketName string, objec // Presign - returns a presigned URL for any http method of your choice // along with custom request params. URL can have a maximum expiry of // upto 7days or a minimum of 1sec. -func (c Client) Presign(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { +func (c *Client) Presign(ctx context.Context, method string, bucketName string, objectName string, expires time.Duration, reqParams url.Values) (u *url.URL, err error) { return c.presignURL(ctx, method, bucketName, objectName, expires, reqParams) } // PresignedPostPolicy - Returns POST urlString, form data to upload an object. -func (c Client) PresignedPostPolicy(ctx context.Context, p *PostPolicy) (u *url.URL, formData map[string]string, err error) { +func (c *Client) PresignedPostPolicy(ctx context.Context, p *PostPolicy) (u *url.URL, formData map[string]string, err error) { // Validate input arguments. if p.expiration.IsZero() { return nil, nil, errors.New("Expiration time must be specified") diff --git a/api-put-bucket.go b/api-put-bucket.go index df9fe98af..441c92230 100644 --- a/api-put-bucket.go +++ b/api-put-bucket.go @@ -27,7 +27,7 @@ import ( ) /// Bucket operations -func (c Client) makeBucket(ctx context.Context, bucketName string, opts MakeBucketOptions) (err error) { +func (c *Client) makeBucket(ctx context.Context, bucketName string, opts MakeBucketOptions) (err error) { // Validate the input arguments. if err := s3utils.CheckValidBucketNameStrict(bucketName); err != nil { return err @@ -42,7 +42,7 @@ func (c Client) makeBucket(ctx context.Context, bucketName string, opts MakeBuck return err } -func (c Client) doMakeBucket(ctx context.Context, bucketName string, location string, objectLockEnabled bool) (err error) { +func (c *Client) doMakeBucket(ctx context.Context, bucketName string, location string, objectLockEnabled bool) (err error) { defer func() { // Save the location into cache on a successful makeBucket response. if err == nil { @@ -118,6 +118,6 @@ type MakeBucketOptions struct { // // For Amazon S3 for more supported regions - http://docs.aws.amazon.com/general/latest/gr/rande.html // For Google Cloud Storage for more supported regions - https://cloud.google.com/storage/docs/bucket-locations -func (c Client) MakeBucket(ctx context.Context, bucketName string, opts MakeBucketOptions) (err error) { +func (c *Client) MakeBucket(ctx context.Context, bucketName string, opts MakeBucketOptions) (err error) { return c.makeBucket(ctx, bucketName, opts) } diff --git a/api-put-object-common.go b/api-put-object-common.go index f1653afe1..638843d46 100644 --- a/api-put-object-common.go +++ b/api-put-object-common.go @@ -130,7 +130,7 @@ func OptimalPartInfo(objectSize int64, configuredPartSize uint64) (totalPartsCou // getUploadID - fetch upload id if already present for an object name // or initiate a new request to fetch a new upload id. -func (c Client) newUploadID(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (uploadID string, err error) { +func (c *Client) newUploadID(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (uploadID string, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return "", err diff --git a/api-put-object-file-context.go b/api-put-object-file-context.go index 6c0f20df3..4d29dfc18 100644 --- a/api-put-object-file-context.go +++ b/api-put-object-file-context.go @@ -27,7 +27,7 @@ import ( ) // FPutObject - Create an object in a bucket, with contents from file at filePath. Allows request cancellation. -func (c Client) FPutObject(ctx context.Context, bucketName, objectName, filePath string, opts PutObjectOptions) (info UploadInfo, err error) { +func (c *Client) FPutObject(ctx context.Context, bucketName, objectName, filePath string, opts PutObjectOptions) (info UploadInfo, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return UploadInfo{}, err diff --git a/api-put-object-multipart.go b/api-put-object-multipart.go index 873ec3878..5d12ab1db 100644 --- a/api-put-object-multipart.go +++ b/api-put-object-multipart.go @@ -37,7 +37,7 @@ import ( "github.com/minio/minio-go/v7/pkg/s3utils" ) -func (c Client) putObjectMultipart(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, +func (c *Client) putObjectMultipart(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { info, err = c.putObjectMultipartNoStream(ctx, bucketName, objectName, reader, opts) if err != nil { @@ -56,7 +56,7 @@ func (c Client) putObjectMultipart(ctx context.Context, bucketName, objectName s return info, err } -func (c Client) putObjectMultipartNoStream(ctx context.Context, bucketName, objectName string, reader io.Reader, opts PutObjectOptions) (info UploadInfo, err error) { +func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, objectName string, reader io.Reader, opts PutObjectOptions) (info UploadInfo, err error) { // Input validation. if err = s3utils.CheckValidBucketName(bucketName); err != nil { return UploadInfo{}, err @@ -186,7 +186,7 @@ func (c Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obje } // initiateMultipartUpload - Initiates a multipart upload and returns an upload ID. -func (c Client) initiateMultipartUpload(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (initiateMultipartUploadResult, error) { +func (c *Client) initiateMultipartUpload(ctx context.Context, bucketName, objectName string, opts PutObjectOptions) (initiateMultipartUploadResult, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return initiateMultipartUploadResult{}, err @@ -237,7 +237,7 @@ func (c Client) initiateMultipartUpload(ctx context.Context, bucketName, objectN } // uploadPart - Uploads a part in a multipart upload. -func (c Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID string, reader io.Reader, +func (c *Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID string, reader io.Reader, partNumber int, md5Base64, sha256Hex string, size int64, sse encrypt.ServerSide) (ObjectPart, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { @@ -308,7 +308,7 @@ func (c Client) uploadPart(ctx context.Context, bucketName, objectName, uploadID } // completeMultipartUpload - Completes a multipart upload by assembling previously uploaded parts. -func (c Client) completeMultipartUpload(ctx context.Context, bucketName, objectName, uploadID string, +func (c *Client) completeMultipartUpload(ctx context.Context, bucketName, objectName, uploadID string, complete completeMultipartUpload, opts PutObjectOptions) (UploadInfo, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { diff --git a/api-put-object-streaming.go b/api-put-object-streaming.go index f1cc9fbb9..928fa315d 100644 --- a/api-put-object-streaming.go +++ b/api-put-object-streaming.go @@ -41,7 +41,7 @@ import ( // - *minio.Object // - Any reader which has a method 'ReadAt()' // -func (c Client) putObjectMultipartStream(ctx context.Context, bucketName, objectName string, +func (c *Client) putObjectMultipartStream(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { if !isObject(reader) && isReadAt(reader) && !opts.SendContentMd5 { @@ -90,7 +90,7 @@ type uploadPartReq struct { // temporary files for staging all the data, these temporary files are // cleaned automatically when the caller i.e http client closes the // stream after uploading all the contents successfully. -func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketName, objectName string, +func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketName, objectName string, reader io.ReaderAt, size int64, opts PutObjectOptions) (info UploadInfo, err error) { // Input validation. if err = s3utils.CheckValidBucketName(bucketName); err != nil { @@ -240,7 +240,7 @@ func (c Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketNa return uploadInfo, nil } -func (c Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, bucketName, objectName string, +func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { // Input validation. if err = s3utils.CheckValidBucketName(bucketName); err != nil { @@ -369,7 +369,7 @@ func (c Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, bu // putObject special function used Google Cloud Storage. This special function // is used for Google Cloud Storage since Google's multipart API is not S3 compatible. -func (c Client) putObject(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { +func (c *Client) putObject(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return UploadInfo{}, err @@ -430,7 +430,7 @@ func (c Client) putObject(ctx context.Context, bucketName, objectName string, re // putObjectDo - executes the put object http operation. // NOTE: You must have WRITE permissions on a bucket to add an object to it. -func (c Client) putObjectDo(ctx context.Context, bucketName, objectName string, reader io.Reader, md5Base64, sha256Hex string, size int64, opts PutObjectOptions) (UploadInfo, error) { +func (c *Client) putObjectDo(ctx context.Context, bucketName, objectName string, reader io.Reader, md5Base64, sha256Hex string, size int64, opts PutObjectOptions) (UploadInfo, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return UploadInfo{}, err diff --git a/api-put-object.go b/api-put-object.go index f669b7d1b..fb61b407a 100644 --- a/api-put-object.go +++ b/api-put-object.go @@ -221,7 +221,7 @@ func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].Part // - For size input as -1 PutObject does a multipart Put operation // until input stream reaches EOF. Maximum object size that can // be uploaded through this operation will be 5TiB. -func (c Client) PutObject(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64, +func (c *Client) PutObject(ctx context.Context, bucketName, objectName string, reader io.Reader, objectSize int64, opts PutObjectOptions) (info UploadInfo, err error) { if objectSize < 0 && opts.DisableMultipart { return UploadInfo{}, errors.New("object size must be provided with disable multipart upload") @@ -235,7 +235,7 @@ func (c Client) PutObject(ctx context.Context, bucketName, objectName string, re return c.putObjectCommon(ctx, bucketName, objectName, reader, objectSize, opts) } -func (c Client) putObjectCommon(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { +func (c *Client) putObjectCommon(ctx context.Context, bucketName, objectName string, reader io.Reader, size int64, opts PutObjectOptions) (info UploadInfo, err error) { // Check for largest object size allowed. if size > int64(maxMultipartPutObjectSize) { return UploadInfo{}, errEntityTooLarge(size, maxMultipartPutObjectSize, bucketName, objectName) @@ -269,7 +269,7 @@ func (c Client) putObjectCommon(ctx context.Context, bucketName, objectName stri return c.putObjectMultipartStream(ctx, bucketName, objectName, reader, size, opts) } -func (c Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName, objectName string, reader io.Reader, opts PutObjectOptions) (info UploadInfo, err error) { +func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketName, objectName string, reader io.Reader, opts PutObjectOptions) (info UploadInfo, err error) { // Input validation. if err = s3utils.CheckValidBucketName(bucketName); err != nil { return UploadInfo{}, err diff --git a/api-remove.go b/api-remove.go index 24e4d3f56..c053a6da2 100644 --- a/api-remove.go +++ b/api-remove.go @@ -40,7 +40,7 @@ type BucketOptions struct { // All objects (including all object versions and delete markers) // in the bucket will be deleted forcibly if bucket options set // ForceDelete to 'true'. -func (c Client) RemoveBucketWithOptions(ctx context.Context, bucketName string, opts BucketOptions) error { +func (c *Client) RemoveBucketWithOptions(ctx context.Context, bucketName string, opts BucketOptions) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -77,7 +77,7 @@ func (c Client) RemoveBucketWithOptions(ctx context.Context, bucketName string, // // All objects (including all object versions and delete markers). // in the bucket must be deleted before successfully attempting this request. -func (c Client) RemoveBucket(ctx context.Context, bucketName string) error { +func (c *Client) RemoveBucket(ctx context.Context, bucketName string) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -120,7 +120,7 @@ type RemoveObjectOptions struct { } // RemoveObject removes an object from a bucket. -func (c Client) RemoveObject(ctx context.Context, bucketName, objectName string, opts RemoveObjectOptions) error { +func (c *Client) RemoveObject(ctx context.Context, bucketName, objectName string, opts RemoveObjectOptions) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -132,7 +132,7 @@ func (c Client) RemoveObject(ctx context.Context, bucketName, objectName string, return c.removeObject(ctx, bucketName, objectName, opts) } -func (c Client) removeObject(ctx context.Context, bucketName, objectName string, opts RemoveObjectOptions) error { +func (c *Client) removeObject(ctx context.Context, bucketName, objectName string, opts RemoveObjectOptions) error { // Get resources properly escaped and lined up before // using them in http request. @@ -246,7 +246,7 @@ type RemoveObjectsOptions struct { // RemoveObjects removes multiple objects from a bucket while // it is possible to specify objects versions which are received from // objectsCh. Remove failures are sent back via error channel. -func (c Client) RemoveObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, opts RemoveObjectsOptions) <-chan RemoveObjectError { +func (c *Client) RemoveObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, opts RemoveObjectsOptions) <-chan RemoveObjectError { errorCh := make(chan RemoveObjectError, 1) // Validate if bucket name is valid. @@ -291,7 +291,7 @@ func hasInvalidXMLChar(str string) bool { } // Generate and call MultiDelete S3 requests based on entries received from objectsCh -func (c Client) removeObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, errorCh chan<- RemoveObjectError, opts RemoveObjectsOptions) { +func (c *Client) removeObjects(ctx context.Context, bucketName string, objectsCh <-chan ObjectInfo, errorCh chan<- RemoveObjectError, opts RemoveObjectsOptions) { maxEntries := 1000 finish := false urlValues := make(url.Values) @@ -389,7 +389,7 @@ func (c Client) removeObjects(ctx context.Context, bucketName string, objectsCh } // RemoveIncompleteUpload aborts an partially uploaded object. -func (c Client) RemoveIncompleteUpload(ctx context.Context, bucketName, objectName string) error { +func (c *Client) RemoveIncompleteUpload(ctx context.Context, bucketName, objectName string) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err @@ -416,7 +416,7 @@ func (c Client) RemoveIncompleteUpload(ctx context.Context, bucketName, objectNa // abortMultipartUpload aborts a multipart upload for the given // uploadID, all previously uploaded parts are deleted. -func (c Client) abortMultipartUpload(ctx context.Context, bucketName, objectName, uploadID string) error { +func (c *Client) abortMultipartUpload(ctx context.Context, bucketName, objectName, uploadID string) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err diff --git a/api-restore.go b/api-restore.go index dd7ce7a38..86d5205dc 100644 --- a/api-restore.go +++ b/api-restore.go @@ -141,7 +141,7 @@ func (r *RestoreRequest) SetOutputLocation(v OutputLocation) { } // RestoreObject is a implementation of https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html AWS S3 API -func (c Client) RestoreObject(ctx context.Context, bucketName, objectName, versionID string, req RestoreRequest) error { +func (c *Client) RestoreObject(ctx context.Context, bucketName, objectName, versionID string, req RestoreRequest) error { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return err diff --git a/api-select.go b/api-select.go index c5e6d3094..74c1df5f1 100644 --- a/api-select.go +++ b/api-select.go @@ -438,7 +438,7 @@ const ( ) // SelectObjectContent is a implementation of http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectSELECTContent.html AWS S3 API. -func (c Client) SelectObjectContent(ctx context.Context, bucketName, objectName string, opts SelectObjectOptions) (*SelectResults, error) { +func (c *Client) SelectObjectContent(ctx context.Context, bucketName, objectName string, opts SelectObjectOptions) (*SelectResults, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return nil, err diff --git a/api-stat.go b/api-stat.go index 12a1bf930..50c750950 100644 --- a/api-stat.go +++ b/api-stat.go @@ -27,7 +27,7 @@ import ( // BucketExists verifies if bucket exists and you have permission to access it. Allows for a Context to // control cancellations and timeouts. -func (c Client) BucketExists(ctx context.Context, bucketName string) (bool, error) { +func (c *Client) BucketExists(ctx context.Context, bucketName string) (bool, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return false, err @@ -58,7 +58,7 @@ func (c Client) BucketExists(ctx context.Context, bucketName string) (bool, erro } // StatObject verifies if object exists and you have permission to access. -func (c Client) StatObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { +func (c *Client) StatObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return ObjectInfo{}, err @@ -70,7 +70,7 @@ func (c Client) StatObject(ctx context.Context, bucketName, objectName string, o } // Lower level API for statObject supporting pre-conditions and range headers. -func (c Client) statObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { +func (c *Client) statObject(ctx context.Context, bucketName, objectName string, opts StatObjectOptions) (ObjectInfo, error) { // Input validation. if err := s3utils.CheckValidBucketName(bucketName); err != nil { return ObjectInfo{}, err diff --git a/api.go b/api.go index 09607c1b9..63b41b7f6 100644 --- a/api.go +++ b/api.go @@ -92,9 +92,7 @@ type Client struct { md5Hasher func() md5simd.Hasher sha256Hasher func() md5simd.Hasher - healthCheckCh chan struct{} - healthCheck int32 - lastOnline time.Time + healthStatus int32 } // Options for New method @@ -312,7 +310,7 @@ func privateNew(endpoint string, opts *Options) (*Client, error) { clnt.lookup = opts.BucketLookup // healthcheck is not initialized - clnt.healthCheck = unknown + clnt.healthStatus = unknown // Return. return clnt, nil @@ -404,30 +402,30 @@ const ( // IsOnline returns true if healthcheck enabled and client is online func (c *Client) IsOnline() bool { - switch atomic.LoadInt32(&c.healthCheck) { - case online, unknown: - return true - } - return false + return !c.IsOffline() +} + +// sets online healthStatus to offline +func (c *Client) markOffline() { + atomic.CompareAndSwapInt32(&c.healthStatus, online, offline) } // IsOffline returns true if healthcheck enabled and client is offline func (c *Client) IsOffline() bool { - return !c.IsOnline() + return atomic.LoadInt32(&c.healthStatus) == offline } // HealthCheck starts a healthcheck to see if endpoint is up. Returns a context cancellation function // and and error if health check is already started func (c *Client) HealthCheck(hcDuration time.Duration) (context.CancelFunc, error) { - if atomic.LoadInt32(&c.healthCheck) == online { - return nil, fmt.Errorf("health check running already") + if atomic.LoadInt32(&c.healthStatus) == online { + return nil, fmt.Errorf("health check is running") } if hcDuration < 1*time.Second { return nil, fmt.Errorf("health check duration should be atleast 1 second") } ctx, cancelFn := context.WithCancel(context.Background()) - c.healthCheckCh = make(chan struct{}) - atomic.StoreInt32(&c.healthCheck, online) + atomic.StoreInt32(&c.healthStatus, online) probeBucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "probe-health-") go func(duration time.Duration) { timer := time.NewTimer(duration) @@ -435,28 +433,24 @@ func (c *Client) HealthCheck(hcDuration time.Duration) (context.CancelFunc, erro for { select { case <-ctx.Done(): - close(c.healthCheckCh) - atomic.StoreInt32(&c.healthCheck, unknown) + atomic.StoreInt32(&c.healthStatus, unknown) return case <-timer.C: - timer.Reset(duration) // Do health check the first time and ONLY if the connection is marked offline - if c.IsOffline() || c.lastOnline.IsZero() { - _, err := c.getBucketLocation(context.Background(), probeBucketName) - if err != nil && IsNetworkOrHostDown(err, false) { - atomic.CompareAndSwapInt32(&c.healthCheck, online, offline) - } else { - switch ToErrorResponse(err).Code { - case "NoSuchBucket", "AccessDenied", "": - c.lastOnline = time.Now() - atomic.CompareAndSwapInt32(&c.healthCheck, offline, online) - } + if c.IsOffline() { + gctx, gcancel := context.WithTimeout(context.Background(), 3*time.Second) + _, err := c.getBucketLocation(gctx, probeBucketName) + gcancel() + if IsNetworkOrHostDown(err, false) { + // Still network errors do not need to do anything. + continue + } + switch ToErrorResponse(err).Code { + case "NoSuchBucket", "AccessDenied", "": + atomic.CompareAndSwapInt32(&c.healthStatus, offline, online) } } - case <-c.healthCheckCh: - // set offline if client saw a network error - atomic.CompareAndSwapInt32(&c.healthCheck, online, offline) } } }(hcDuration) @@ -484,7 +478,7 @@ type requestMetadata struct { } // dumpHTTP - dump HTTP request and response. -func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error { +func (c *Client) dumpHTTP(req *http.Request, resp *http.Response) error { // Starts http dump. _, err := fmt.Fprintln(c.traceOutput, "---------START-HTTP---------") if err != nil { @@ -544,8 +538,14 @@ func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error { } // do - execute http request. -func (c Client) do(req *http.Request) (*http.Response, error) { - resp, err := c.httpClient.Do(req) +func (c *Client) do(req *http.Request) (resp *http.Response, err error) { + defer func() { + if IsNetworkOrHostDown(err, false) { + c.markOffline() + } + }() + + resp, err = c.httpClient.Do(req) if err != nil { // Handle this specifically for now until future Golang versions fix this issue properly. if urlErr, ok := err.(*url.Error); ok { @@ -588,7 +588,11 @@ var successStatus = []int{ // executeMethod - instantiates a given method, and retries the // request upon any error up to maxRetries attempts in a binomially // delayed manner using a standard back off algorithm. -func (c Client) executeMethod(ctx context.Context, method string, metadata requestMetadata) (res *http.Response, err error) { +func (c *Client) executeMethod(ctx context.Context, method string, metadata requestMetadata) (res *http.Response, err error) { + if c.IsOffline() { + return nil, errors.New(c.endpointURL.String() + " is offline.") + } + var retryable bool // Indicates if request can be retried. var bodySeeker io.Seeker // Extracted seeker from io.Reader. var reqRetry = MaxRetry // Indicates how many times we can retry the request @@ -642,24 +646,11 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque continue // Retry. } - if atomic.LoadInt32(&c.healthCheck) != unknown && IsNetworkOrHostDown(err, false) { - select { - case c.healthCheckCh <- struct{}{}: - default: - } - } return nil, err } // Initiate the request. res, err = c.do(req) if err != nil { - if atomic.LoadInt32(&c.healthCheck) != unknown && IsNetworkOrHostDown(err, false) { - select { - case c.healthCheckCh <- struct{}{}: - default: - } - } - if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { return nil, err } @@ -754,7 +745,7 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque } // newRequest - instantiate a new HTTP request for a given method. -func (c Client) newRequest(ctx context.Context, method string, metadata requestMetadata) (req *http.Request, err error) { +func (c *Client) newRequest(ctx context.Context, method string, metadata requestMetadata) (req *http.Request, err error) { // If no method is supplied default to 'POST'. if method == "" { method = http.MethodPost @@ -894,7 +885,7 @@ func (c Client) newRequest(ctx context.Context, method string, metadata requestM } // set User agent. -func (c Client) setUserAgent(req *http.Request) { +func (c *Client) setUserAgent(req *http.Request) { req.Header.Set("User-Agent", libraryUserAgent) if c.appInfo.appName != "" && c.appInfo.appVersion != "" { req.Header.Set("User-Agent", libraryUserAgent+" "+c.appInfo.appName+"/"+c.appInfo.appVersion) @@ -902,7 +893,7 @@ func (c Client) setUserAgent(req *http.Request) { } // makeTargetURL make a new target url. -func (c Client) makeTargetURL(bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) { +func (c *Client) makeTargetURL(bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) { host := c.endpointURL.Host // For Amazon S3 endpoint, try to fetch location based endpoint. if s3utils.IsAmazonEndpoint(*c.endpointURL) { diff --git a/bucket-cache.go b/bucket-cache.go index 156150f62..760af7751 100644 --- a/bucket-cache.go +++ b/bucket-cache.go @@ -73,7 +73,7 @@ func (r *bucketLocationCache) Delete(bucketName string) { // GetBucketLocation - get location for the bucket name from location cache, if not // fetch freshly by making a new request. -func (c Client) GetBucketLocation(ctx context.Context, bucketName string) (string, error) { +func (c *Client) GetBucketLocation(ctx context.Context, bucketName string) (string, error) { if err := s3utils.CheckValidBucketName(bucketName); err != nil { return "", err } @@ -82,7 +82,7 @@ func (c Client) GetBucketLocation(ctx context.Context, bucketName string) (strin // getBucketLocation - Get location for the bucketName from location map cache, if not // fetch freshly by making a new request. -func (c Client) getBucketLocation(ctx context.Context, bucketName string) (string, error) { +func (c *Client) getBucketLocation(ctx context.Context, bucketName string) (string, error) { if err := s3utils.CheckValidBucketName(bucketName); err != nil { return "", err } @@ -169,7 +169,7 @@ func processBucketLocationResponse(resp *http.Response, bucketName string) (buck } // getBucketLocationRequest - Wrapper creates a new getBucketLocation request. -func (c Client) getBucketLocationRequest(ctx context.Context, bucketName string) (*http.Request, error) { +func (c *Client) getBucketLocationRequest(ctx context.Context, bucketName string) (*http.Request, error) { // Set location query. urlValues := make(url.Values) urlValues.Set("location", "") diff --git a/healthcheck_test.go b/healthcheck_test.go new file mode 100644 index 000000000..54f3c7afc --- /dev/null +++ b/healthcheck_test.go @@ -0,0 +1,69 @@ +/* + * MinIO Go Library for Amazon S3 Compatible Cloud Storage + * Copyright 2021 MinIO, Inc. + * + * 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 minio + +import ( + "context" + "math/rand" + "net/http" + "net/http/httptest" + "testing" + "time" +) + +func TestHealthCheck(t *testing.T) { + srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer srv.Close() + + // New - instantiate minio client with options + clnt, err := New(srv.Listener.Addr().String(), &Options{ + Region: "us-east-1", + }) + if err != nil { + t.Fatal(err) + } + + hcancel, err := clnt.HealthCheck(1 * time.Second) + if err != nil { + t.Fatal(err) + } + + probeBucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "probe-health-") + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + clnt.BucketExists(ctx, probeBucketName) + + if !clnt.IsOffline() { + t.Fatal("Expected offline but found online") + } + + srv.Start() + time.Sleep(2 * time.Second) + + if clnt.IsOffline() { + t.Fatal("Expected online but found offline") + } + + hcancel() // healthcheck is canceled. + + if !clnt.IsOnline() { + t.Fatal("Expected online but found offline") + } +} diff --git a/retry-continous.go b/retry-continous.go index 3d25883b0..12b81d91a 100644 --- a/retry-continous.go +++ b/retry-continous.go @@ -20,7 +20,7 @@ package minio import "time" // newRetryTimerContinous creates a timer with exponentially increasing delays forever. -func (c Client) newRetryTimerContinous(unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int { +func (c *Client) newRetryTimerContinous(unit time.Duration, cap time.Duration, jitter float64, doneCh chan struct{}) <-chan int { attemptCh := make(chan int) // normalize jitter to the range [0, 1.0] diff --git a/retry.go b/retry.go index 598af2975..a449d55dd 100644 --- a/retry.go +++ b/retry.go @@ -42,7 +42,7 @@ var DefaultRetryCap = time.Second // newRetryTimer creates a timer with exponentially increasing // delays until the maximum retry attempts are reached. -func (c Client) newRetryTimer(ctx context.Context, maxRetry int, unit time.Duration, cap time.Duration, jitter float64) <-chan int { +func (c *Client) newRetryTimer(ctx context.Context, maxRetry int, unit time.Duration, cap time.Duration, jitter float64) <-chan int { attemptCh := make(chan int) // computes the exponential backoff duration according to diff --git a/utils.go b/utils.go index f5ce3118d..6c1c8c512 100644 --- a/utils.go +++ b/utils.go @@ -552,6 +552,11 @@ func IsNetworkOrHostDown(err error, expectTimeouts bool) bool { if expectTimeouts && errors.Is(err, context.DeadlineExceeded) { return false } + + if errors.Is(err, context.DeadlineExceeded) { + return true + } + // We need to figure if the error either a timeout // or a non-temporary error. urlErr := &url.Error{}