mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
Fix storage class related issues (#5338)
- Update startup banner to print storage class in capitals. This makes it easier to identify different storage classes available. - Update response metadata to not send STANDARD storage class. This is in accordance with AWS S3 behaviour. - Update minio-go library to bring in storage class related changes. This is needed to make transparent translation of storage class headers for Minio S3 Gateway.
This commit is contained in:
parent
6f7c6fc560
commit
1e5fb4b79a
@ -122,7 +122,7 @@ func (m fsMetaV1) ToObjectInfo(bucket, object string, fi os.FileInfo) ObjectInfo
|
|||||||
// etag/md5Sum has already been extracted. We need to
|
// etag/md5Sum has already been extracted. We need to
|
||||||
// remove to avoid it from appearing as part of
|
// remove to avoid it from appearing as part of
|
||||||
// response headers. e.g, X-Minio-* or X-Amz-*.
|
// response headers. e.g, X-Minio-* or X-Amz-*.
|
||||||
objInfo.UserDefined = cleanMetaETag(m.Meta)
|
objInfo.UserDefined = cleanMetadata(m.Meta)
|
||||||
|
|
||||||
// Success..
|
// Success..
|
||||||
return objInfo
|
return objInfo
|
||||||
|
@ -187,14 +187,26 @@ func getCompleteMultipartMD5(parts []CompletePart) (string, error) {
|
|||||||
return s3MD5, nil
|
return s3MD5, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean meta etag keys 'md5Sum', 'etag'.
|
// Clean unwanted fields from metadata
|
||||||
func cleanMetaETag(metadata map[string]string) map[string]string {
|
func cleanMetadata(metadata map[string]string) map[string]string {
|
||||||
return cleanMetadata(metadata, "md5Sum", "etag")
|
// Remove STANDARD StorageClass
|
||||||
|
metadata = removeStandardStorageClass(metadata)
|
||||||
|
// Clean meta etag keys 'md5Sum', 'etag'.
|
||||||
|
return cleanMetadataKeys(metadata, "md5Sum", "etag")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean metadata takes keys to be filtered
|
// Filter X-Amz-Storage-Class field only if it is set to STANDARD.
|
||||||
// and returns a new map with the keys filtered.
|
// This is done since AWS S3 doesn't return STANDARD Storage class as response header.
|
||||||
func cleanMetadata(metadata map[string]string, keyNames ...string) map[string]string {
|
func removeStandardStorageClass(metadata map[string]string) map[string]string {
|
||||||
|
if metadata[amzStorageClass] == standardStorageClass {
|
||||||
|
delete(metadata, amzStorageClass)
|
||||||
|
}
|
||||||
|
return metadata
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanMetadataKeys takes keyNames to be filtered
|
||||||
|
// and returns a new map with all the entries with keyNames removed.
|
||||||
|
func cleanMetadataKeys(metadata map[string]string, keyNames ...string) map[string]string {
|
||||||
var newMeta = make(map[string]string)
|
var newMeta = make(map[string]string)
|
||||||
for k, v := range metadata {
|
for k, v := range metadata {
|
||||||
if contains(keyNames, k) {
|
if contains(keyNames, k) {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -197,3 +198,100 @@ func TestIsMinioMetaBucketName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests RemoveStandardStorageClass method. Expectation is metadata map
|
||||||
|
// should be cleared of x-amz-storage-class, if it is set to STANDARD
|
||||||
|
func TestRemoveStandardStorageClass(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
metadata map[string]string
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "STANDARD"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "REDUCED_REDUNDANCY"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "REDUCED_REDUNDANCY"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
if got := removeStandardStorageClass(tt.metadata); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Test %s failed, expected %v, got %v", tt.name, tt.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests CleanMetadata method. Expectation is metadata map
|
||||||
|
// should be cleared of etag, md5Sum and x-amz-storage-class, if it is set to STANDARD
|
||||||
|
func TestCleanMetadata(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
metadata map[string]string
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "STANDARD"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "REDUCED_REDUNDANCY"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream", "x-amz-storage-class": "REDUCED_REDUNDANCY"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "md5Sum": "abcde"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
if got := cleanMetadata(tt.metadata); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Test %s failed, expected %v, got %v", tt.name, tt.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests CleanMetadataKeys method. Expectation is metadata map
|
||||||
|
// should be cleared of keys passed to CleanMetadataKeys method
|
||||||
|
func TestCleanMetadataKeys(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
metadata map[string]string
|
||||||
|
keys []string
|
||||||
|
want map[string]string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "STANDARD", "md5": "abcde"},
|
||||||
|
keys: []string{"etag", "md5"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream", "x-amz-storage-class": "STANDARD"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "x-amz-storage-class": "REDUCED_REDUNDANCY", "md5sum": "abcde"},
|
||||||
|
keys: []string{"etag", "md5sum"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream", "x-amz-storage-class": "REDUCED_REDUNDANCY"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3",
|
||||||
|
metadata: map[string]string{"content-type": "application/octet-stream", "etag": "de75a98baf2c6aef435b57dd0fc33c86", "xyz": "abcde"},
|
||||||
|
keys: []string{"etag", "xyz"},
|
||||||
|
want: map[string]string{"content-type": "application/octet-stream"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
if got := cleanMetadataKeys(tt.metadata, tt.keys...); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Test %s failed, expected %v, got %v", tt.name, tt.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -198,7 +198,7 @@ func printStorageClassInfoMsg(storageInfo StorageInfo) {
|
|||||||
func getStandardStorageClassInfoMsg(storageInfo StorageInfo) string {
|
func getStandardStorageClassInfoMsg(storageInfo StorageInfo) string {
|
||||||
var msg string
|
var msg string
|
||||||
if maxDiskFailures := storageInfo.Backend.standardSCParity - storageInfo.Backend.OfflineDisks; maxDiskFailures >= 0 {
|
if maxDiskFailures := storageInfo.Backend.standardSCParity - storageInfo.Backend.OfflineDisks; maxDiskFailures >= 0 {
|
||||||
msg += fmt.Sprintf("Objects with Standard class can withstand [%d] drive failure(s).\n", maxDiskFailures)
|
msg += fmt.Sprintf("Objects with "+standardStorageClass+" class can withstand [%d] drive failure(s).\n", maxDiskFailures)
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
@ -206,7 +206,7 @@ func getStandardStorageClassInfoMsg(storageInfo StorageInfo) string {
|
|||||||
func getRRSStorageClassInfoMsg(storageInfo StorageInfo) string {
|
func getRRSStorageClassInfoMsg(storageInfo StorageInfo) string {
|
||||||
var msg string
|
var msg string
|
||||||
if maxDiskFailures := storageInfo.Backend.rrSCParity - storageInfo.Backend.OfflineDisks; maxDiskFailures >= 0 {
|
if maxDiskFailures := storageInfo.Backend.rrSCParity - storageInfo.Backend.OfflineDisks; maxDiskFailures >= 0 {
|
||||||
msg += fmt.Sprintf("Objects with Reduced Redundancy class can withstand [%d] drive failure(s).\n", maxDiskFailures)
|
msg += fmt.Sprintf("Objects with "+reducedRedundancyStorageClass+" class can withstand [%d] drive failure(s).\n", maxDiskFailures)
|
||||||
}
|
}
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ func TestGetStandardStorageClassInfoMsg(t *testing.T) {
|
|||||||
standardSCParity int
|
standardSCParity int
|
||||||
rrSCParity int
|
rrSCParity int
|
||||||
}{Erasure, 15, 1, 5, 3},
|
}{Erasure, 15, 1, 5, 3},
|
||||||
}, "Objects with Standard class can withstand [4] drive failure(s).\n"},
|
}, "Objects with " + standardStorageClass + " class can withstand [4] drive failure(s).\n"},
|
||||||
{"2", StorageInfo{
|
{"2", StorageInfo{
|
||||||
Total: 30 * humanize.GiByte,
|
Total: 30 * humanize.GiByte,
|
||||||
Free: 3 * humanize.GiByte,
|
Free: 3 * humanize.GiByte,
|
||||||
@ -183,7 +183,7 @@ func TestGetStandardStorageClassInfoMsg(t *testing.T) {
|
|||||||
standardSCParity int
|
standardSCParity int
|
||||||
rrSCParity int
|
rrSCParity int
|
||||||
}{Erasure, 10, 0, 5, 3},
|
}{Erasure, 10, 0, 5, 3},
|
||||||
}, "Objects with Standard class can withstand [5] drive failure(s).\n"},
|
}, "Objects with " + standardStorageClass + " class can withstand [5] drive failure(s).\n"},
|
||||||
{"3", StorageInfo{
|
{"3", StorageInfo{
|
||||||
Total: 15 * humanize.GiByte,
|
Total: 15 * humanize.GiByte,
|
||||||
Free: 2 * humanize.GiByte,
|
Free: 2 * humanize.GiByte,
|
||||||
@ -194,7 +194,7 @@ func TestGetStandardStorageClassInfoMsg(t *testing.T) {
|
|||||||
standardSCParity int
|
standardSCParity int
|
||||||
rrSCParity int
|
rrSCParity int
|
||||||
}{Erasure, 12, 3, 6, 2},
|
}{Erasure, 12, 3, 6, 2},
|
||||||
}, "Objects with Standard class can withstand [3] drive failure(s).\n"},
|
}, "Objects with " + standardStorageClass + " class can withstand [3] drive failure(s).\n"},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
if got := getStandardStorageClassInfoMsg(tt.args); got != tt.want {
|
if got := getStandardStorageClassInfoMsg(tt.args); got != tt.want {
|
||||||
@ -219,7 +219,7 @@ func TestGetRRSStorageClassInfoMsg(t *testing.T) {
|
|||||||
standardSCParity int
|
standardSCParity int
|
||||||
rrSCParity int
|
rrSCParity int
|
||||||
}{Erasure, 15, 1, 5, 3},
|
}{Erasure, 15, 1, 5, 3},
|
||||||
}, "Objects with Reduced Redundancy class can withstand [2] drive failure(s).\n"},
|
}, "Objects with " + reducedRedundancyStorageClass + " class can withstand [2] drive failure(s).\n"},
|
||||||
{"2", StorageInfo{
|
{"2", StorageInfo{
|
||||||
Total: 30 * humanize.GiByte,
|
Total: 30 * humanize.GiByte,
|
||||||
Free: 3 * humanize.GiByte,
|
Free: 3 * humanize.GiByte,
|
||||||
@ -230,7 +230,7 @@ func TestGetRRSStorageClassInfoMsg(t *testing.T) {
|
|||||||
standardSCParity int
|
standardSCParity int
|
||||||
rrSCParity int
|
rrSCParity int
|
||||||
}{Erasure, 16, 0, 5, 3},
|
}{Erasure, 16, 0, 5, 3},
|
||||||
}, "Objects with Reduced Redundancy class can withstand [3] drive failure(s).\n"},
|
}, "Objects with " + reducedRedundancyStorageClass + " class can withstand [3] drive failure(s).\n"},
|
||||||
{"3", StorageInfo{
|
{"3", StorageInfo{
|
||||||
Total: 15 * humanize.GiByte,
|
Total: 15 * humanize.GiByte,
|
||||||
Free: 2 * humanize.GiByte,
|
Free: 2 * humanize.GiByte,
|
||||||
@ -241,7 +241,7 @@ func TestGetRRSStorageClassInfoMsg(t *testing.T) {
|
|||||||
standardSCParity int
|
standardSCParity int
|
||||||
rrSCParity int
|
rrSCParity int
|
||||||
}{Erasure, 12, 3, 6, 5},
|
}{Erasure, 12, 3, 6, 5},
|
||||||
}, "Objects with Reduced Redundancy class can withstand [2] drive failure(s).\n"},
|
}, "Objects with " + reducedRedundancyStorageClass + " class can withstand [2] drive failure(s).\n"},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
if got := getRRSStorageClassInfoMsg(tt.args); got != tt.want {
|
if got := getRRSStorageClassInfoMsg(tt.args); got != tt.want {
|
||||||
|
@ -296,7 +296,7 @@ func (m xlMetaV1) ToObjectInfo(bucket, object string) ObjectInfo {
|
|||||||
// etag/md5Sum has already been extracted. We need to
|
// etag/md5Sum has already been extracted. We need to
|
||||||
// remove to avoid it from appearing as part of
|
// remove to avoid it from appearing as part of
|
||||||
// response headers. e.g, X-Minio-* or X-Amz-*.
|
// response headers. e.g, X-Minio-* or X-Amz-*.
|
||||||
objInfo.UserDefined = cleanMetaETag(m.Meta)
|
objInfo.UserDefined = cleanMetadata(m.Meta)
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
return objInfo
|
return objInfo
|
||||||
|
@ -347,7 +347,7 @@ func (xl xlObjects) getObjectInfo(bucket, object string) (objInfo ObjectInfo, er
|
|||||||
// etag/md5Sum has already been extracted. We need to
|
// etag/md5Sum has already been extracted. We need to
|
||||||
// remove to avoid it from appearing as part of
|
// remove to avoid it from appearing as part of
|
||||||
// response headers. e.g, X-Minio-* or X-Amz-*.
|
// response headers. e.g, X-Minio-* or X-Amz-*.
|
||||||
objInfo.UserDefined = cleanMetaETag(xlMetaMap)
|
objInfo.UserDefined = cleanMetadata(xlMetaMap)
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
return objInfo, nil
|
return objInfo, nil
|
||||||
|
2
vendor/github.com/minio/minio-go/Makefile
generated
vendored
2
vendor/github.com/minio/minio-go/Makefile
generated
vendored
@ -2,7 +2,7 @@ all: checks
|
|||||||
|
|
||||||
checks:
|
checks:
|
||||||
@go get -u github.com/go-ini/ini/...
|
@go get -u github.com/go-ini/ini/...
|
||||||
@go get -u github.com/minio/go-homedir/...
|
@go get -u github.com/mitchellh/go-homedir/...
|
||||||
@go get -u github.com/cheggaaa/pb/...
|
@go get -u github.com/cheggaaa/pb/...
|
||||||
@go get -u github.com/sirupsen/logrus/...
|
@go get -u github.com/sirupsen/logrus/...
|
||||||
@go get -u github.com/dustin/go-humanize/...
|
@go get -u github.com/dustin/go-humanize/...
|
||||||
|
246
vendor/github.com/minio/minio-go/README_zh_CN.md
generated
vendored
Normal file
246
vendor/github.com/minio/minio-go/README_zh_CN.md
generated
vendored
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
# 适用于与Amazon S3兼容云存储的Minio Go SDK [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io) [![Sourcegraph](https://sourcegraph.com/github.com/minio/minio-go/-/badge.svg)](https://sourcegraph.com/github.com/minio/minio-go?badge)
|
||||||
|
|
||||||
|
Minio Go Client SDK提供了简单的API来访问任何与Amazon S3兼容的对象存储服务。
|
||||||
|
|
||||||
|
**支持的云存储:**
|
||||||
|
|
||||||
|
- AWS Signature Version 4
|
||||||
|
- Amazon S3
|
||||||
|
- Minio
|
||||||
|
|
||||||
|
- AWS Signature Version 2
|
||||||
|
- Google Cloud Storage (兼容模式)
|
||||||
|
- Openstack Swift + Swift3 middleware
|
||||||
|
- Ceph Object Gateway
|
||||||
|
- Riak CS
|
||||||
|
|
||||||
|
本文我们将学习如何安装Minio client SDK,连接到Minio,并提供一下文件上传的示例。对于完整的API以及示例,请参考[Go Client API Reference](https://docs.minio.io/docs/golang-client-api-reference)。
|
||||||
|
|
||||||
|
本文假设你已经有 [Go开发环境](https://docs.minio.io/docs/how-to-install-golang)。
|
||||||
|
|
||||||
|
## 从Github下载
|
||||||
|
```sh
|
||||||
|
go get -u github.com/minio/minio-go
|
||||||
|
```
|
||||||
|
|
||||||
|
## 初始化Minio Client
|
||||||
|
Minio client需要以下4个参数来连接与Amazon S3兼容的对象存储。
|
||||||
|
|
||||||
|
| 参数 | 描述|
|
||||||
|
| :--- | :--- |
|
||||||
|
| endpoint | 对象存储服务的URL |
|
||||||
|
| accessKeyID | Access key是唯一标识你的账户的用户ID。 |
|
||||||
|
| secretAccessKey | Secret key是你账户的密码。 |
|
||||||
|
| secure | true代表使用HTTPS |
|
||||||
|
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/minio/minio-go"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
endpoint := "play.minio.io:9000"
|
||||||
|
accessKeyID := "Q3AM3UQ867SPQQA43P2F"
|
||||||
|
secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
|
||||||
|
useSSL := true
|
||||||
|
|
||||||
|
// 初使化 minio client对象。
|
||||||
|
minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("%#v\n", minioClient) // minioClient初使化成功
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 示例-文件上传
|
||||||
|
本示例连接到一个对象存储服务,创建一个存储桶并上传一个文件到存储桶中。
|
||||||
|
|
||||||
|
我们在本示例中使用运行在 [https://play.minio.io:9000](https://play.minio.io:9000) 上的Minio服务,你可以用这个服务来开发和测试。示例中的访问凭据是公开的。
|
||||||
|
|
||||||
|
### FileUploader.go
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/minio/minio-go"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
endpoint := "play.minio.io:9000"
|
||||||
|
accessKeyID := "Q3AM3UQ867SPQQA43P2F"
|
||||||
|
secretAccessKey := "zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG"
|
||||||
|
useSSL := true
|
||||||
|
|
||||||
|
// 初使化minio client对象。
|
||||||
|
minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个叫mymusic的存储桶。
|
||||||
|
bucketName := "mymusic"
|
||||||
|
location := "us-east-1"
|
||||||
|
|
||||||
|
err = minioClient.MakeBucket(bucketName, location)
|
||||||
|
if err != nil {
|
||||||
|
// 检查存储桶是否已经存在。
|
||||||
|
exists, err := minioClient.BucketExists(bucketName)
|
||||||
|
if err == nil && exists {
|
||||||
|
log.Printf("We already own %s\n", bucketName)
|
||||||
|
} else {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("Successfully created %s\n", bucketName)
|
||||||
|
|
||||||
|
// 上传一个zip文件。
|
||||||
|
objectName := "golden-oldies.zip"
|
||||||
|
filePath := "/tmp/golden-oldies.zip"
|
||||||
|
contentType := "application/zip"
|
||||||
|
|
||||||
|
// 使用FPutObject上传一个zip文件。
|
||||||
|
n, err := minioClient.FPutObject(bucketName, objectName, filePath, minio.PutObjectOptions{ContentType:contentType})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully uploaded %s of size %d\n", objectName, n)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 运行FileUploader
|
||||||
|
```sh
|
||||||
|
go run file-uploader.go
|
||||||
|
2016/08/13 17:03:28 Successfully created mymusic
|
||||||
|
2016/08/13 17:03:40 Successfully uploaded golden-oldies.zip of size 16253413
|
||||||
|
|
||||||
|
mc ls play/mymusic/
|
||||||
|
[2016-05-27 16:02:16 PDT] 17MiB golden-oldies.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
## API文档
|
||||||
|
完整的API文档在这里。
|
||||||
|
* [完整API文档](https://docs.minio.io/docs/golang-client-api-reference)
|
||||||
|
|
||||||
|
### API文档 : 操作存储桶
|
||||||
|
* [`MakeBucket`](https://docs.minio.io/docs/golang-client-api-reference#MakeBucket)
|
||||||
|
* [`ListBuckets`](https://docs.minio.io/docs/golang-client-api-reference#ListBuckets)
|
||||||
|
* [`BucketExists`](https://docs.minio.io/docs/golang-client-api-reference#BucketExists)
|
||||||
|
* [`RemoveBucket`](https://docs.minio.io/docs/golang-client-api-reference#RemoveBucket)
|
||||||
|
* [`ListObjects`](https://docs.minio.io/docs/golang-client-api-reference#ListObjects)
|
||||||
|
* [`ListObjectsV2`](https://docs.minio.io/docs/golang-client-api-reference#ListObjectsV2)
|
||||||
|
* [`ListIncompleteUploads`](https://docs.minio.io/docs/golang-client-api-reference#ListIncompleteUploads)
|
||||||
|
|
||||||
|
### API文档 : 存储桶策略
|
||||||
|
* [`SetBucketPolicy`](https://docs.minio.io/docs/golang-client-api-reference#SetBucketPolicy)
|
||||||
|
* [`GetBucketPolicy`](https://docs.minio.io/docs/golang-client-api-reference#GetBucketPolicy)
|
||||||
|
* [`ListBucketPolicies`](https://docs.minio.io/docs/golang-client-api-reference#ListBucketPolicies)
|
||||||
|
|
||||||
|
### API文档 : 存储桶通知
|
||||||
|
* [`SetBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#SetBucketNotification)
|
||||||
|
* [`GetBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#GetBucketNotification)
|
||||||
|
* [`RemoveAllBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#RemoveAllBucketNotification)
|
||||||
|
* [`ListenBucketNotification`](https://docs.minio.io/docs/golang-client-api-reference#ListenBucketNotification) (Minio Extension)
|
||||||
|
|
||||||
|
### API文档 : 操作文件对象
|
||||||
|
* [`FPutObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject)
|
||||||
|
* [`FGetObject`](https://docs.minio.io/docs/golang-client-api-reference#FPutObject)
|
||||||
|
* [`FPutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FPutObjectWithContext)
|
||||||
|
* [`FGetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#FGetObjectWithContext)
|
||||||
|
|
||||||
|
### API文档 : 操作对象
|
||||||
|
* [`GetObject`](https://docs.minio.io/docs/golang-client-api-reference#GetObject)
|
||||||
|
* [`PutObject`](https://docs.minio.io/docs/golang-client-api-reference#PutObject)
|
||||||
|
* [`GetObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#GetObjectWithContext)
|
||||||
|
* [`PutObjectWithContext`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectWithContext)
|
||||||
|
* [`PutObjectStreaming`](https://docs.minio.io/docs/golang-client-api-reference#PutObjectStreaming)
|
||||||
|
* [`StatObject`](https://docs.minio.io/docs/golang-client-api-reference#StatObject)
|
||||||
|
* [`CopyObject`](https://docs.minio.io/docs/golang-client-api-reference#CopyObject)
|
||||||
|
* [`RemoveObject`](https://docs.minio.io/docs/golang-client-api-reference#RemoveObject)
|
||||||
|
* [`RemoveObjects`](https://docs.minio.io/docs/golang-client-api-reference#RemoveObjects)
|
||||||
|
* [`RemoveIncompleteUpload`](https://docs.minio.io/docs/golang-client-api-reference#RemoveIncompleteUpload)
|
||||||
|
|
||||||
|
### API文档: 操作加密对象
|
||||||
|
* [`GetEncryptedObject`](https://docs.minio.io/docs/golang-client-api-reference#GetEncryptedObject)
|
||||||
|
* [`PutEncryptedObject`](https://docs.minio.io/docs/golang-client-api-reference#PutEncryptedObject)
|
||||||
|
|
||||||
|
### API文档 : Presigned操作
|
||||||
|
* [`PresignedGetObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedGetObject)
|
||||||
|
* [`PresignedPutObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedPutObject)
|
||||||
|
* [`PresignedHeadObject`](https://docs.minio.io/docs/golang-client-api-reference#PresignedHeadObject)
|
||||||
|
* [`PresignedPostPolicy`](https://docs.minio.io/docs/golang-client-api-reference#PresignedPostPolicy)
|
||||||
|
|
||||||
|
### API文档 : 客户端自定义设置
|
||||||
|
* [`SetAppInfo`](http://docs.minio.io/docs/golang-client-api-reference#SetAppInfo)
|
||||||
|
* [`SetCustomTransport`](http://docs.minio.io/docs/golang-client-api-reference#SetCustomTransport)
|
||||||
|
* [`TraceOn`](http://docs.minio.io/docs/golang-client-api-reference#TraceOn)
|
||||||
|
* [`TraceOff`](http://docs.minio.io/docs/golang-client-api-reference#TraceOff)
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
### 完整示例 : 操作存储桶
|
||||||
|
* [makebucket.go](https://github.com/minio/minio-go/blob/master/examples/s3/makebucket.go)
|
||||||
|
* [listbuckets.go](https://github.com/minio/minio-go/blob/master/examples/s3/listbuckets.go)
|
||||||
|
* [bucketexists.go](https://github.com/minio/minio-go/blob/master/examples/s3/bucketexists.go)
|
||||||
|
* [removebucket.go](https://github.com/minio/minio-go/blob/master/examples/s3/removebucket.go)
|
||||||
|
* [listobjects.go](https://github.com/minio/minio-go/blob/master/examples/s3/listobjects.go)
|
||||||
|
* [listobjectsV2.go](https://github.com/minio/minio-go/blob/master/examples/s3/listobjectsV2.go)
|
||||||
|
* [listincompleteuploads.go](https://github.com/minio/minio-go/blob/master/examples/s3/listincompleteuploads.go)
|
||||||
|
|
||||||
|
### 完整示例 : 存储桶策略
|
||||||
|
* [setbucketpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketpolicy.go)
|
||||||
|
* [getbucketpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketpolicy.go)
|
||||||
|
* [listbucketpolicies.go](https://github.com/minio/minio-go/blob/master/examples/s3/listbucketpolicies.go)
|
||||||
|
|
||||||
|
### 完整示例 : 存储桶通知
|
||||||
|
* [setbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/setbucketnotification.go)
|
||||||
|
* [getbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/getbucketnotification.go)
|
||||||
|
* [removeallbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeallbucketnotification.go)
|
||||||
|
* [listenbucketnotification.go](https://github.com/minio/minio-go/blob/master/examples/minio/listenbucketnotification.go) (Minio扩展)
|
||||||
|
|
||||||
|
### 完整示例 : 操作文件对象
|
||||||
|
* [fputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject.go)
|
||||||
|
* [fgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject.go)
|
||||||
|
* [fputobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputobject-context.go)
|
||||||
|
* [fgetobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/fgetobject-context.go)
|
||||||
|
|
||||||
|
### 完整示例 : 操作对象
|
||||||
|
* [putobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject.go)
|
||||||
|
* [getobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject.go)
|
||||||
|
* [putobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/putobject-context.go)
|
||||||
|
* [getobject-context.go](https://github.com/minio/minio-go/blob/master/examples/s3/getobject-context.go)
|
||||||
|
* [statobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/statobject.go)
|
||||||
|
* [copyobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/copyobject.go)
|
||||||
|
* [removeobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobject.go)
|
||||||
|
* [removeincompleteupload.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeincompleteupload.go)
|
||||||
|
* [removeobjects.go](https://github.com/minio/minio-go/blob/master/examples/s3/removeobjects.go)
|
||||||
|
|
||||||
|
### 完整示例 : 操作加密对象
|
||||||
|
* [put-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/put-encrypted-object.go)
|
||||||
|
* [get-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/get-encrypted-object.go)
|
||||||
|
* [fput-encrypted-object.go](https://github.com/minio/minio-go/blob/master/examples/s3/fputencrypted-object.go)
|
||||||
|
|
||||||
|
### 完整示例 : Presigned操作
|
||||||
|
* [presignedgetobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedgetobject.go)
|
||||||
|
* [presignedputobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedputobject.go)
|
||||||
|
* [presignedheadobject.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedheadobject.go)
|
||||||
|
* [presignedpostpolicy.go](https://github.com/minio/minio-go/blob/master/examples/s3/presignedpostpolicy.go)
|
||||||
|
|
||||||
|
## 了解更多
|
||||||
|
* [完整文档](https://docs.minio.io)
|
||||||
|
* [Minio Go Client SDK API文档](https://docs.minio.io/docs/golang-client-api-reference)
|
||||||
|
* [Go 音乐播放器完整示例](https://docs.minio.io/docs/go-music-player-app)
|
||||||
|
|
||||||
|
## 贡献
|
||||||
|
[贡献指南](https://github.com/minio/minio-go/blob/master/docs/zh_CN/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/minio/minio-go.svg)](https://travis-ci.org/minio/minio-go)
|
||||||
|
[![Build status](https://ci.appveyor.com/api/projects/status/1d05e6nvxcelmrak?svg=true)](https://ci.appveyor.com/project/harshavardhana/minio-go)
|
||||||
|
|
2
vendor/github.com/minio/minio-go/api-datatypes.go
generated
vendored
2
vendor/github.com/minio/minio-go/api-datatypes.go
generated
vendored
@ -44,7 +44,7 @@ type ObjectInfo struct {
|
|||||||
|
|
||||||
// Collection of additional metadata on the object.
|
// Collection of additional metadata on the object.
|
||||||
// eg: x-amz-meta-*, content-encoding etc.
|
// eg: x-amz-meta-*, content-encoding etc.
|
||||||
Metadata http.Header `json:"metadata"`
|
Metadata http.Header `json:"metadata" xml:"-"`
|
||||||
|
|
||||||
// Owner name.
|
// Owner name.
|
||||||
Owner struct {
|
Owner struct {
|
||||||
|
1
vendor/github.com/minio/minio-go/api-put-object-streaming.go
generated
vendored
1
vendor/github.com/minio/minio-go/api-put-object-streaming.go
generated
vendored
@ -381,7 +381,6 @@ func (c Client) putObjectDo(ctx context.Context, bucketName, objectName string,
|
|||||||
}
|
}
|
||||||
// Set headers.
|
// Set headers.
|
||||||
customHeader := opts.Header()
|
customHeader := opts.Header()
|
||||||
|
|
||||||
// Populate request metadata.
|
// Populate request metadata.
|
||||||
reqMetadata := requestMetadata{
|
reqMetadata := requestMetadata{
|
||||||
bucketName: bucketName,
|
bucketName: bucketName,
|
||||||
|
10
vendor/github.com/minio/minio-go/api-put-object.go
generated
vendored
10
vendor/github.com/minio/minio-go/api-put-object.go
generated
vendored
@ -40,6 +40,7 @@ type PutObjectOptions struct {
|
|||||||
CacheControl string
|
CacheControl string
|
||||||
EncryptMaterials encrypt.Materials
|
EncryptMaterials encrypt.Materials
|
||||||
NumThreads uint
|
NumThreads uint
|
||||||
|
StorageClass string
|
||||||
}
|
}
|
||||||
|
|
||||||
// getNumThreads - gets the number of threads to be used in the multipart
|
// getNumThreads - gets the number of threads to be used in the multipart
|
||||||
@ -77,8 +78,11 @@ func (opts PutObjectOptions) Header() (header http.Header) {
|
|||||||
header[amzHeaderKey] = []string{opts.EncryptMaterials.GetKey()}
|
header[amzHeaderKey] = []string{opts.EncryptMaterials.GetKey()}
|
||||||
header[amzHeaderMatDesc] = []string{opts.EncryptMaterials.GetDesc()}
|
header[amzHeaderMatDesc] = []string{opts.EncryptMaterials.GetDesc()}
|
||||||
}
|
}
|
||||||
|
if opts.StorageClass != "" {
|
||||||
|
header[amzStorageClass] = []string{opts.StorageClass}
|
||||||
|
}
|
||||||
for k, v := range opts.UserMetadata {
|
for k, v := range opts.UserMetadata {
|
||||||
if !isAmzHeader(k) && !isStandardHeader(k) && !isSSEHeader(k) {
|
if !isAmzHeader(k) && !isStandardHeader(k) && !isSSEHeader(k) && !isStorageClassHeader(k) {
|
||||||
header["X-Amz-Meta-"+k] = []string{v}
|
header["X-Amz-Meta-"+k] = []string{v}
|
||||||
} else {
|
} else {
|
||||||
header[k] = []string{v}
|
header[k] = []string{v}
|
||||||
@ -91,8 +95,8 @@ func (opts PutObjectOptions) Header() (header http.Header) {
|
|||||||
// encryption headers and raises an error if so.
|
// encryption headers and raises an error if so.
|
||||||
func (opts PutObjectOptions) validate() (err error) {
|
func (opts PutObjectOptions) validate() (err error) {
|
||||||
for k := range opts.UserMetadata {
|
for k := range opts.UserMetadata {
|
||||||
if isStandardHeader(k) || isCSEHeader(k) {
|
if isStandardHeader(k) || isCSEHeader(k) || isStorageClassHeader(k) {
|
||||||
return ErrInvalidArgument(k + " unsupported request parameter for user defined metadata")
|
return ErrInvalidArgument(k + " unsupported request parameter for user defined metadata from minio-go")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
2
vendor/github.com/minio/minio-go/api.go
generated
vendored
2
vendor/github.com/minio/minio-go/api.go
generated
vendored
@ -86,7 +86,7 @@ type Client struct {
|
|||||||
// Global constants.
|
// Global constants.
|
||||||
const (
|
const (
|
||||||
libraryName = "minio-go"
|
libraryName = "minio-go"
|
||||||
libraryVersion = "4.0.4"
|
libraryVersion = "4.0.6"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User Agent should always following the below style.
|
// User Agent should always following the below style.
|
||||||
|
2
vendor/github.com/minio/minio-go/appveyor.yml
generated
vendored
2
vendor/github.com/minio/minio-go/appveyor.yml
generated
vendored
@ -18,7 +18,7 @@ install:
|
|||||||
- go env
|
- go env
|
||||||
- go get -u github.com/golang/lint/golint
|
- go get -u github.com/golang/lint/golint
|
||||||
- go get -u github.com/go-ini/ini
|
- go get -u github.com/go-ini/ini
|
||||||
- go get -u github.com/minio/go-homedir
|
- go get -u github.com/mitchellh/go-homedir
|
||||||
- go get -u github.com/remyoudompheng/go-misc/deadcode
|
- go get -u github.com/remyoudompheng/go-misc/deadcode
|
||||||
- go get -u github.com/gordonklaus/ineffassign
|
- go get -u github.com/gordonklaus/ineffassign
|
||||||
- go get -u github.com/dustin/go-humanize
|
- go get -u github.com/dustin/go-humanize
|
||||||
|
3
vendor/github.com/minio/minio-go/constants.go
generated
vendored
3
vendor/github.com/minio/minio-go/constants.go
generated
vendored
@ -65,3 +65,6 @@ const (
|
|||||||
amzHeaderKey = "X-Amz-Meta-X-Amz-Key"
|
amzHeaderKey = "X-Amz-Meta-X-Amz-Key"
|
||||||
amzHeaderMatDesc = "X-Amz-Meta-X-Amz-Matdesc"
|
amzHeaderMatDesc = "X-Amz-Meta-X-Amz-Matdesc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Storage class header constant.
|
||||||
|
const amzStorageClass = "X-Amz-Storage-Class"
|
||||||
|
6939
vendor/github.com/minio/minio-go/functional_tests.go
generated
vendored
Normal file
6939
vendor/github.com/minio/minio-go/functional_tests.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
5
vendor/github.com/minio/minio-go/utils.go
generated
vendored
5
vendor/github.com/minio/minio-go/utils.go
generated
vendored
@ -234,6 +234,11 @@ var cseHeaders = []string{
|
|||||||
"X-Amz-Matdesc",
|
"X-Amz-Matdesc",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isStorageClassHeader returns true if the header is a supported storage class header
|
||||||
|
func isStorageClassHeader(headerKey string) bool {
|
||||||
|
return strings.ToLower(amzStorageClass) == strings.ToLower(headerKey)
|
||||||
|
}
|
||||||
|
|
||||||
// isStandardHeader returns true if header is a supported header and not a custom header
|
// isStandardHeader returns true if header is a supported header and not a custom header
|
||||||
func isStandardHeader(headerKey string) bool {
|
func isStandardHeader(headerKey string) bool {
|
||||||
key := strings.ToLower(headerKey)
|
key := strings.ToLower(headerKey)
|
||||||
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
@ -402,10 +402,10 @@
|
|||||||
"revisionTime": "2016-02-29T08:42:30-08:00"
|
"revisionTime": "2016-02-29T08:42:30-08:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "EjYaYvofsB9eAyRXSwRLXX12778=",
|
"checksumSHA1": "wPmY8+2/EZHIgrrqCVk21Z4+TCc=",
|
||||||
"path": "github.com/minio/minio-go",
|
"path": "github.com/minio/minio-go",
|
||||||
"revision": "b3f9ea44f05f3fc176fc2c510e7922be09f709d4",
|
"revision": "93f1e8b8551b56c54dcb6b0fbb459546f54d9774",
|
||||||
"revisionTime": "2017-11-20T20:37:48Z"
|
"revisionTime": "2017-12-24T05:09:42Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"checksumSHA1": "5juljGXPkBWENR2Os7dlnPQER48=",
|
"checksumSHA1": "5juljGXPkBWENR2Os7dlnPQER48=",
|
||||||
|
Loading…
Reference in New Issue
Block a user