Skip to content

Commit a4af737

Browse files
committed
s3: Support Alibaba Cloud (Aliyun) OSS
The existing s3 backend passed all integration tests with OSS provided `force_path_style = false`. This makes sure that is so and adds documentation and configuration for OSS. Fixes #1641 Fixes #1237
1 parent 781142a commit a4af737

File tree

5 files changed

+230
-65
lines changed

5 files changed

+230
-65
lines changed

CONTRIBUTING.md

-1
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,3 @@ Add your fs to the docs - you'll need to pick an icon for it from [fontawesome](
372372
* `docs/content/about.md` - front page of rclone.org
373373
* `docs/layouts/chrome/navbar.html` - add it to the website navigation
374374
* `bin/make_manual.py` - add the page to the `docs` constant
375-
* `cmd/cmd.go` - the main help for rclone

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Rclone *("rsync for cloud storage")* is a command line program to sync files and
2020

2121
## Storage providers
2222

23+
* Alibaba Cloud (Aliyun) Object Storage System (OSS) [:page_facing_up:](https://rclone.org/s3/#alibaba-oss)
2324
* Amazon Drive [:page_facing_up:](https://rclone.org/amazonclouddrive/) ([See note](https://rclone.org/amazonclouddrive/#status))
2425
* Amazon S3 [:page_facing_up:](https://rclone.org/s3/)
2526
* Backblaze B2 [:page_facing_up:](https://rclone.org/b2/)

backend/s3/s3.go

+93-8
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,17 @@ import (
5353
func init() {
5454
fs.Register(&fs.RegInfo{
5555
Name: "s3",
56-
Description: "Amazon S3 Compliant Storage Providers (AWS, Ceph, Dreamhost, IBM COS, Minio)",
56+
Description: "Amazon S3 Compliant Storage Provider (AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, etc)",
5757
NewFs: NewFs,
5858
Options: []fs.Option{{
5959
Name: fs.ConfigProvider,
6060
Help: "Choose your S3 provider.",
6161
Examples: []fs.OptionExample{{
6262
Value: "AWS",
6363
Help: "Amazon Web Services (AWS) S3",
64+
}, {
65+
Value: "Alibaba",
66+
Help: "Alibaba Cloud Object Storage System (OSS) formerly Aliyun",
6467
}, {
6568
Value: "Ceph",
6669
Help: "Ceph Object Storage",
@@ -76,6 +79,9 @@ func init() {
7679
}, {
7780
Value: "Minio",
7881
Help: "Minio Object Storage",
82+
}, {
83+
Value: "Netease",
84+
Help: "Netease Object Storage (NOS)",
7985
}, {
8086
Value: "Wasabi",
8187
Help: "Wasabi Object Storage",
@@ -150,7 +156,7 @@ func init() {
150156
}, {
151157
Name: "region",
152158
Help: "Region to connect to.\nLeave blank if you are using an S3 clone and you don't have a region.",
153-
Provider: "!AWS",
159+
Provider: "!AWS,Alibaba",
154160
Examples: []fs.OptionExample{{
155161
Value: "",
156162
Help: "Use this if unsure. Will use v4 signatures and an empty region.",
@@ -269,10 +275,73 @@ func init() {
269275
Value: "s3.tor01.objectstorage.service.networklayer.com",
270276
Help: "Toronto Single Site Private Endpoint",
271277
}},
278+
}, {
279+
// oss endpoints: https://help.aliyun.com/document_detail/31837.html
280+
Name: "endpoint",
281+
Help: "Endpoint for OSS API.",
282+
Provider: "Alibaba",
283+
Examples: []fs.OptionExample{{
284+
Value: "oss-cn-hangzhou.aliyuncs.com",
285+
Help: "East China 1 (Hangzhou)",
286+
}, {
287+
Value: "oss-cn-shanghai.aliyuncs.com",
288+
Help: "East China 2 (Shanghai)",
289+
}, {
290+
Value: "oss-cn-qingdao.aliyuncs.com",
291+
Help: "North China 1 (Qingdao)",
292+
}, {
293+
Value: "oss-cn-beijing.aliyuncs.com",
294+
Help: "North China 2 (Beijing)",
295+
}, {
296+
Value: "oss-cn-zhangjiakou.aliyuncs.com",
297+
Help: "North China 3 (Zhangjiakou)",
298+
}, {
299+
Value: "oss-cn-huhehaote.aliyuncs.com",
300+
Help: "North China 5 (Huhehaote)",
301+
}, {
302+
Value: "oss-cn-shenzhen.aliyuncs.com",
303+
Help: "South China 1 (Shenzhen)",
304+
}, {
305+
Value: "oss-cn-hongkong.aliyuncs.com",
306+
Help: "Hong Kong (Hong Kong)",
307+
}, {
308+
Value: "oss-us-west-1.aliyuncs.com",
309+
Help: "US West 1 (Silicon Valley)",
310+
}, {
311+
Value: "oss-us-east-1.aliyuncs.com",
312+
Help: "US East 1 (Virginia)",
313+
}, {
314+
Value: "oss-ap-southeast-1.aliyuncs.com",
315+
Help: "Southeast Asia Southeast 1 (Singapore)",
316+
}, {
317+
Value: "oss-ap-southeast-2.aliyuncs.com",
318+
Help: "Asia Pacific Southeast 2 (Sydney)",
319+
}, {
320+
Value: "oss-ap-southeast-3.aliyuncs.com",
321+
Help: "Southeast Asia Southeast 3 (Kuala Lumpur)",
322+
}, {
323+
Value: "oss-ap-southeast-5.aliyuncs.com",
324+
Help: "Asia Pacific Southeast 5 (Jakarta)",
325+
}, {
326+
Value: "oss-ap-northeast-1.aliyuncs.com",
327+
Help: "Asia Pacific Northeast 1 (Japan)",
328+
}, {
329+
Value: "oss-ap-south-1.aliyuncs.com",
330+
Help: "Asia Pacific South 1 (Mumbai)",
331+
}, {
332+
Value: "oss-eu-central-1.aliyuncs.com",
333+
Help: "Central Europe 1 (Frankfurt)",
334+
}, {
335+
Value: "oss-eu-west-1.aliyuncs.com",
336+
Help: "West Europe (London)",
337+
}, {
338+
Value: "oss-me-east-1.aliyuncs.com",
339+
Help: "Middle East 1 (Dubai)",
340+
}},
272341
}, {
273342
Name: "endpoint",
274343
Help: "Endpoint for S3 API.\nRequired when using an S3 clone.",
275-
Provider: "!AWS,IBMCOS",
344+
Provider: "!AWS,IBMCOS,Alibaba",
276345
Examples: []fs.OptionExample{{
277346
Value: "objects-us-west-1.dream.io",
278347
Help: "Dream Objects endpoint",
@@ -449,7 +518,7 @@ func init() {
449518
}, {
450519
Name: "location_constraint",
451520
Help: "Location constraint - must be set to match the Region.\nLeave blank if not sure. Used when creating buckets only.",
452-
Provider: "!AWS,IBMCOS",
521+
Provider: "!AWS,IBMCOS,Alibaba",
453522
}, {
454523
Name: "acl",
455524
Help: `Canned ACL used when creating buckets and storing or copying objects.
@@ -547,6 +616,20 @@ doesn't copy the ACL from the source but rather writes a fresh one.`,
547616
Value: "GLACIER",
548617
Help: "Glacier storage class",
549618
}},
619+
}, {
620+
Name: "storage_class",
621+
Help: "The storage class to use when storing new objects in OSS.",
622+
Provider: "Alibaba",
623+
Examples: []fs.OptionExample{{
624+
Value: "Standard",
625+
Help: "Standard storage class",
626+
}, {
627+
Value: "Archive",
628+
Help: "Archive storage mode.",
629+
}, {
630+
Value: "IA",
631+
Help: "Infrequent access storage mode.",
632+
}},
550633
}, {
551634
Name: "upload_cutoff",
552635
Help: `Cutoff for switching to chunked upload
@@ -714,22 +797,21 @@ func (f *Fs) Features() *fs.Features {
714797
// retryErrorCodes is a slice of error codes that we will retry
715798
// See: https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html
716799
var retryErrorCodes = []int{
717-
409, // Conflict - various states that could be resolved on a retry
800+
// 409, // Conflict - various states that could be resolved on a retry
718801
503, // Service Unavailable/Slow Down - "Reduce your request rate"
719802
}
720803

721804
//S3 is pretty resilient, and the built in retry handling is probably sufficient
722805
// as it should notice closed connections and timeouts which are the most likely
723806
// sort of failure modes
724807
func shouldRetry(err error) (bool, error) {
725-
726808
// If this is an awserr object, try and extract more useful information to determine if we should retry
727809
if awsError, ok := err.(awserr.Error); ok {
728810
// Simple case, check the original embedded error in case it's generically retriable
729811
if fserrors.ShouldRetry(awsError.OrigErr()) {
730812
return true, err
731813
}
732-
//Failing that, if it's a RequestFailure it's probably got an http status code we can check
814+
// Failing that, if it's a RequestFailure it's probably got an http status code we can check
733815
if reqErr, ok := err.(awserr.RequestFailure); ok {
734816
for _, e := range retryErrorCodes {
735817
if reqErr.StatusCode() == e {
@@ -738,7 +820,7 @@ func shouldRetry(err error) (bool, error) {
738820
}
739821
}
740822
}
741-
//Ok, not an awserr, check for generic failure conditions
823+
// Ok, not an awserr, check for generic failure conditions
742824
return fserrors.ShouldRetry(err), err
743825
}
744826

@@ -815,6 +897,9 @@ func s3Connection(opt *Options) (*s3.S3, *session.Session, error) {
815897
if opt.Region == "" {
816898
opt.Region = "us-east-1"
817899
}
900+
if opt.Provider == "Alibaba" || opt.Provider == "Netease" {
901+
opt.ForcePathStyle = false
902+
}
818903
awsConfig := aws.NewConfig().
819904
WithRegion(opt.Region).
820905
WithMaxRetries(maxRetries).

docs/content/about.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Rclone
1313

1414
Rclone is a command line program to sync files and directories to and from:
1515

16+
* {{< provider name="Alibaba Cloud (Aliyun) Object Storage System (OSS)" home="https://www.alibabacloud.com/product/oss/" config="/s3/#alibaba-oss" >}}
1617
* {{< provider name="Amazon Drive" home="https://www.amazon.com/clouddrive" config="/amazonclouddrive/" >}} ([See note](/amazonclouddrive/#status))
1718
* {{< provider name="Amazon S3" home="https://aws.amazon.com/s3/" config="/s3/" >}}
1819
* {{< provider name="Backblaze B2" home="https://www.backblaze.com/b2/cloud-storage.html" config="/b2/" >}}

0 commit comments

Comments
 (0)