mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-28 19:45:07 +08:00
s3gateway phase2
This commit is contained in:
@@ -196,4 +196,52 @@ func init() {
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetAclOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
ACL string `help:"ACL to set" choices:"default|private|public-read|public-read-write"`
|
||||
Key string `help:"Optional object key"`
|
||||
}
|
||||
R(&BucketSetAclOptions{}, "bucket-set-acl", "Set ACL of bucket or object", func(s *mcclient.ClientSession, args *BucketSetAclOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "acl", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketAclOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
Key string `help:"Optional object key"`
|
||||
}
|
||||
R(&BucketAclOptions{}, "bucket-acl", "Get ACL of bucket or object", func(s *mcclient.ClientSession, args *BucketAclOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Buckets.GetSpecific(s, args.ID, "acl", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSyncOptions struct {
|
||||
ID string `help:"ID or name of bucket" json:"-"`
|
||||
}
|
||||
R(&BucketSyncOptions{}, "bucket-sync", "Sync bucket", func(s *mcclient.ClientSession, args *BucketSyncOptions) error {
|
||||
result, err := modules.Buckets.PerformAction(s, args.ID, "sync", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -213,4 +213,21 @@ func init() {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
type CloudproviderStorageClassesOptions struct {
|
||||
ID string `help:"ID or Name of cloud provider" json:"-"`
|
||||
Cloudregion string `help:"cloud region name or Id"`
|
||||
}
|
||||
R(&CloudproviderStorageClassesOptions{}, "cloud-provider-storage-classes", "Get list of supported storage classes of a cloud provider", func(s *mcclient.ClientSession, args *CloudproviderStorageClassesOptions) error {
|
||||
params, err := options.StructToParams(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result, err := modules.Cloudproviders.GetSpecific(s, args.ID, "storage-classes", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
post:
|
||||
summary: 设置存储桶或者对象的ACL
|
||||
parameters:
|
||||
- $ref: '../parameters/bucket.yaml#/bucket_name'
|
||||
- name: bucket
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: "../schemas/bucket.yaml#/BucketSetACLInput"
|
||||
responses:
|
||||
200:
|
||||
description: 指定存储桶或者对象的ACL响应
|
||||
schema:
|
||||
$ref: "../schemas/bucket.yaml#/BucketGetResponse"
|
||||
tags:
|
||||
- buckets
|
||||
|
||||
get:
|
||||
summary: 获取存储桶或者对象的ACL
|
||||
parameters:
|
||||
- $ref: '../parameters/bucket.yaml#/bucket_name'
|
||||
- name: key
|
||||
in: query
|
||||
type: string
|
||||
description: 如果查询对象的ACL,通过key指定对象的名称
|
||||
responses:
|
||||
200:
|
||||
description: 指定存储桶或者对象的ACL响应
|
||||
schema:
|
||||
$ref: "../schemas/bucket.yaml#/BucketGetACLResponse"
|
||||
tags:
|
||||
- buckets
|
||||
@@ -441,6 +441,8 @@ paths:
|
||||
$ref: "./bucket/uploadobject.yaml"
|
||||
/buckets/{bucketName}/tempurl:
|
||||
$ref: "./bucket/tempurl.yaml"
|
||||
/buckets/{bucketName}/acl:
|
||||
$ref: "./bucket/acl.yaml"
|
||||
|
||||
/ansibleplaybooks:
|
||||
$ref: "./ansibleplaybook/ansibleplaybooks.yaml"
|
||||
|
||||
@@ -98,9 +98,21 @@ Bucket:
|
||||
can_delete:
|
||||
type: boolean
|
||||
description: 是否可以删除
|
||||
acl:
|
||||
type: string
|
||||
description: 存储桶的默认访问权限,可能值为:private, public-read和public-read-write
|
||||
storage_class:
|
||||
type: string
|
||||
description: 存储桶的默认存储类型
|
||||
access_urls:
|
||||
type: object
|
||||
description: 存储桶的访问URL信息
|
||||
object_cnt:
|
||||
type: integer
|
||||
description: 对象总数量
|
||||
size_bytes:
|
||||
type: integer
|
||||
description: 对象的总大小(bytes)
|
||||
tenant_id:
|
||||
type: string
|
||||
description: 存储桶归属的项目ID
|
||||
@@ -167,9 +179,30 @@ BucketObjectTempUrlResponse:
|
||||
type: string
|
||||
description: 生成的临时URL
|
||||
|
||||
BucketGetACLResponse:
|
||||
type: object
|
||||
properties:
|
||||
bucket:
|
||||
type: object
|
||||
properties:
|
||||
acl:
|
||||
type: string
|
||||
description: bucket或者对象的ACL字串,可能为private, public-read, public-read-write, default(仅object支持)
|
||||
|
||||
BucketMakedirInput:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: 目录的名称,必需以"/"结尾
|
||||
|
||||
BucketSetACLInput:
|
||||
type: object
|
||||
properties:
|
||||
acl:
|
||||
type: string
|
||||
required: true
|
||||
description: bucket或者对象的ACL字串,可能为private, public-read, public-read-write, default(仅object支持)
|
||||
key:
|
||||
type: string
|
||||
description: 如果设置对象的ACL,则此字段指定对象的key
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package compute
|
||||
|
||||
const (
|
||||
BUCKET_OPS_STATS_CHANGE = "stats_change"
|
||||
|
||||
BUCKET_STATUS_START_CREATE = "start_create"
|
||||
BUCKET_STATUS_CREATING = "creating"
|
||||
BUCKET_STATUS_READY = "ready"
|
||||
|
||||
@@ -52,6 +52,8 @@ type ICloudProviderFactory interface {
|
||||
IsOnPremise() bool
|
||||
IsSupportPrepaidResources() bool
|
||||
NeedSyncSkuFromCloud() bool
|
||||
|
||||
IsSupportObjectStorage() bool
|
||||
}
|
||||
|
||||
type ICloudProvider interface {
|
||||
@@ -69,10 +71,13 @@ type ICloudProvider interface {
|
||||
GetBalance() (float64, string, error)
|
||||
|
||||
GetSubAccounts() ([]SSubAccount, error)
|
||||
GetAccountId() string
|
||||
|
||||
// region external id 是以provider 做为前缀.因此可以通过该判断条件过滤出同一个provider的regions列表
|
||||
// 但是华为云有点特殊一个provider只对应一个region,因此需要进一步指定region名字,才能找到provider对应的region
|
||||
GetCloudRegionExternalIdPrefix() string
|
||||
|
||||
GetStorageClasses(regionId string) []string
|
||||
}
|
||||
|
||||
var providerTable map[string]ICloudProviderFactory
|
||||
@@ -123,13 +128,16 @@ func IsSupported(provider string) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
func IsValidCloudAccount(accessUrl, account, secret, provider string) error {
|
||||
func IsValidCloudAccount(accessUrl, account, secret, provider string) (string, error) {
|
||||
factory, ok := providerTable[provider]
|
||||
if ok {
|
||||
_, err := factory.GetProvider("", "", accessUrl, account, secret)
|
||||
return err
|
||||
provider, err := factory.GetProvider("", "", accessUrl, account, secret)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return provider.GetAccountId(), nil
|
||||
} else {
|
||||
return ErrNoSuchProvder
|
||||
return "", ErrNoSuchProvder
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +234,10 @@ func (factory *SPremiseBaseProviderFactory) IsOnPremise() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (factory *SPremiseBaseProviderFactory) IsSupportObjectStorage() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (factory *SPremiseBaseProviderFactory) NeedSyncSkuFromCloud() bool {
|
||||
return false
|
||||
}
|
||||
@@ -242,6 +254,10 @@ func (factory *SPublicCloudBaseProviderFactor) IsSupportPrepaidResources() bool
|
||||
return true
|
||||
}
|
||||
|
||||
func (factory *SPublicCloudBaseProviderFactor) IsSupportObjectStorage() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (factory *SPublicCloudBaseProviderFactor) NeedSyncSkuFromCloud() bool {
|
||||
return false
|
||||
}
|
||||
@@ -258,6 +274,10 @@ func (factory *SPrivateCloudBaseProviderFactor) IsSupportPrepaidResources() bool
|
||||
return false
|
||||
}
|
||||
|
||||
func (factory *SPrivateCloudBaseProviderFactor) IsSupportObjectStorage() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (factory *SPrivateCloudBaseProviderFactor) NeedSyncSkuFromCloud() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -21,9 +21,35 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/minio-go"
|
||||
"yunion.io/x/pkg/errors"
|
||||
)
|
||||
|
||||
type TBucketACLType string
|
||||
|
||||
const (
|
||||
ACLDefault = TBucketACLType("default")
|
||||
|
||||
ACLPrivate = TBucketACLType(minio.CANNED_ACL_PRIVATE)
|
||||
ACLAuthRead = TBucketACLType(minio.CANNED_ACL_AUTH_READ)
|
||||
ACLPublicRead = TBucketACLType(minio.CANNED_ACL_PUBLIC_READ)
|
||||
ACLPublicReadWrite = TBucketACLType(minio.CANNED_ACL_PUBLIC_READ_WRITE)
|
||||
ACLUnknown = TBucketACLType("")
|
||||
)
|
||||
|
||||
type SBucketStats struct {
|
||||
SizeBytes int64
|
||||
ObjectCount int
|
||||
}
|
||||
|
||||
func (s SBucketStats) Equals(s2 SBucketStats) bool {
|
||||
if s.SizeBytes == s2.SizeBytes && s.ObjectCount == s2.ObjectCount {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type SBucketAccessUrl struct {
|
||||
Url string
|
||||
Description string
|
||||
@@ -50,12 +76,15 @@ type ICloudBucket interface {
|
||||
|
||||
//GetGlobalId() string
|
||||
//GetName() string
|
||||
GetAcl() string
|
||||
GetAcl() TBucketACLType
|
||||
GetLocation() string
|
||||
GetIRegion() ICloudRegion
|
||||
GetCreateAt() time.Time
|
||||
GetStorageClass() string
|
||||
GetAccessUrls() []SBucketAccessUrl
|
||||
GetStats() SBucketStats
|
||||
|
||||
SetAcl(acl TBucketACLType) error
|
||||
|
||||
ListObjects(prefix string, marker string, delimiter string, maxCount int) (SListObjectResult, error)
|
||||
GetIObjects(prefix string, isRecursive bool) ([]ICloudObject, error)
|
||||
@@ -74,6 +103,9 @@ type ICloudObject interface {
|
||||
GetStorageClass() string
|
||||
GetETag() string
|
||||
GetContentType() string
|
||||
|
||||
GetAcl() TBucketACLType
|
||||
SetAcl(acl TBucketACLType) error
|
||||
}
|
||||
|
||||
func ICloudObject2BaseCloudObject(obj ICloudObject) SBaseCloudObject {
|
||||
@@ -124,6 +156,34 @@ func GetIBucketById(region ICloudRegion, name string) (ICloudBucket, error) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
func GetIBucketByName(region ICloudRegion, name string) (ICloudBucket, error) {
|
||||
buckets, err := region.GetIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.GetIBuckets")
|
||||
}
|
||||
for i := range buckets {
|
||||
if buckets[i].GetName() == name {
|
||||
return buckets[i], nil
|
||||
}
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
func GetIBucketStats(bucket ICloudBucket) (SBucketStats, error) {
|
||||
stats := SBucketStats{}
|
||||
objs, err := bucket.GetIObjects("", true)
|
||||
if err != nil {
|
||||
stats.ObjectCount = -1
|
||||
stats.SizeBytes = -1
|
||||
return stats, errors.Wrap(err, "GetIObjects")
|
||||
}
|
||||
for _, obj := range objs {
|
||||
stats.SizeBytes += obj.GetSizeBytes()
|
||||
stats.ObjectCount += 1
|
||||
}
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
func GetIObjects(bucket ICloudBucket, objectPrefix string, isRecursive bool) ([]ICloudObject, error) {
|
||||
delimiter := "/"
|
||||
if isRecursive {
|
||||
|
||||
@@ -118,6 +118,7 @@ type ICloudRegion interface {
|
||||
DeleteIBucket(name string) error
|
||||
IBucketExist(name string) (bool, error)
|
||||
GetIBucketById(name string) (ICloudBucket, error)
|
||||
GetIBucketByName(name string) (ICloudBucket, error)
|
||||
|
||||
GetIDBInstances() ([]ICloudDBInstance, error)
|
||||
GetIDBInstanceBackups() ([]ICloudDBInstanceBackup, error)
|
||||
|
||||
+198
-20
@@ -70,6 +70,11 @@ type SBucket struct {
|
||||
StorageClass string `width:"36" charset:"ascii" nullable:"false" list:"user"`
|
||||
Location string `width:"36" charset:"ascii" nullable:"false" list:"user"`
|
||||
Acl string `width:"36" charset:"ascii" nullable:"false" list:"user"`
|
||||
|
||||
SizeBytes int64 `nullable:"false" default:"0" list:"user"`
|
||||
ObjectCnt int `nullable:"false" default:"0" list:"user"`
|
||||
|
||||
AccessUrls jsonutils.JSONObject `nullable:"true" list:"user"`
|
||||
}
|
||||
|
||||
func (manager *SBucketManager) SetHandlerProcessTimeout(info *appsrv.SHandlerInfo, r *http.Request) time.Duration {
|
||||
@@ -128,7 +133,7 @@ func (manager *SBucketManager) syncBuckets(ctx context.Context, userCred mcclien
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(commondb); i += 1 {
|
||||
err = commondb[i].syncWithCloudBucket(ctx, userCred, commonext[i], provider)
|
||||
err = commondb[i].syncWithCloudBucket(ctx, userCred, commonext[i], provider, false)
|
||||
if err != nil {
|
||||
syncResult.UpdateError(err)
|
||||
} else {
|
||||
@@ -176,7 +181,13 @@ func (manager *SBucketManager) newFromCloudBucket(
|
||||
|
||||
bucket.Location = extBucket.GetLocation()
|
||||
bucket.StorageClass = extBucket.GetStorageClass()
|
||||
// bucket.Acl = extBucket.GetAcl()
|
||||
bucket.Acl = string(extBucket.GetAcl())
|
||||
|
||||
stats := extBucket.GetStats()
|
||||
bucket.SizeBytes = stats.SizeBytes
|
||||
bucket.ObjectCnt = stats.ObjectCount
|
||||
|
||||
bucket.AccessUrls = jsonutils.Marshal(extBucket.GetAccessUrls())
|
||||
|
||||
bucket.IsEmulated = false
|
||||
|
||||
@@ -192,18 +203,45 @@ func (manager *SBucketManager) newFromCloudBucket(
|
||||
return &bucket, nil
|
||||
}
|
||||
|
||||
func (bucket *SBucket) getStats() cloudprovider.SBucketStats {
|
||||
return cloudprovider.SBucketStats{
|
||||
SizeBytes: bucket.SizeBytes,
|
||||
ObjectCount: bucket.ObjectCnt,
|
||||
}
|
||||
}
|
||||
|
||||
func (bucket *SBucket) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
|
||||
desc := bucket.SVirtualResourceBase.GetShortDesc(ctx)
|
||||
desc.Add(jsonutils.NewInt(bucket.SizeBytes), "size_bytes")
|
||||
desc.Add(jsonutils.NewInt(int64(bucket.ObjectCnt)), "object_cnt")
|
||||
desc.Add(jsonutils.NewString(bucket.Acl), "acl")
|
||||
desc.Add(jsonutils.NewString(bucket.StorageClass), "storage_class")
|
||||
return desc
|
||||
}
|
||||
|
||||
func (bucket *SBucket) syncWithCloudBucket(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
extBucket cloudprovider.ICloudBucket,
|
||||
provider *SCloudprovider,
|
||||
statsOnly bool,
|
||||
) error {
|
||||
oStats := bucket.getStats()
|
||||
diff, err := db.UpdateWithLock(ctx, bucket, func() error {
|
||||
// bucket.Acl = extBucket.GetAcl()
|
||||
bucket.Location = extBucket.GetLocation()
|
||||
bucket.StorageClass = extBucket.GetStorageClass()
|
||||
stats := extBucket.GetStats()
|
||||
bucket.SizeBytes = stats.SizeBytes
|
||||
bucket.ObjectCnt = stats.ObjectCount
|
||||
|
||||
if !statsOnly {
|
||||
bucket.Acl = string(extBucket.GetAcl())
|
||||
bucket.Location = extBucket.GetLocation()
|
||||
bucket.StorageClass = extBucket.GetStorageClass()
|
||||
|
||||
bucket.AccessUrls = jsonutils.Marshal(extBucket.GetAccessUrls())
|
||||
|
||||
bucket.Status = api.BUCKET_STATUS_READY
|
||||
}
|
||||
|
||||
bucket.Status = api.BUCKET_STATUS_READY
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -212,6 +250,10 @@ func (bucket *SBucket) syncWithCloudBucket(
|
||||
|
||||
db.OpsLog.LogSyncUpdate(bucket, diff, userCred)
|
||||
|
||||
if !oStats.Equals(extBucket.GetStats()) {
|
||||
db.OpsLog.LogEvent(bucket, api.BUCKET_OPS_STATS_CHANGE, bucket.GetShortDesc(ctx), userCred)
|
||||
}
|
||||
|
||||
if provider != nil {
|
||||
SyncCloudProject(userCred, bucket, provider.GetOwnerId(), extBucket, provider.Id)
|
||||
}
|
||||
@@ -244,15 +286,17 @@ func (bucket *SBucket) RealDelete(ctx context.Context, userCred mcclient.TokenCr
|
||||
}
|
||||
|
||||
func (bucket *SBucket) RemoteDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
iregion, err := bucket.GetIRegion()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bucket.GetIRegion")
|
||||
if len(bucket.ExternalId) > 0 {
|
||||
iregion, err := bucket.GetIRegion()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bucket.GetIRegion")
|
||||
}
|
||||
err = iregion.DeleteIBucket(bucket.ExternalId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "iregion.DeleteIBucket")
|
||||
}
|
||||
}
|
||||
err = iregion.DeleteIBucket(bucket.ExternalId)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "iregion.DeleteIBucket")
|
||||
}
|
||||
err = bucket.RealDelete(ctx, userCred)
|
||||
err := bucket.RealDelete(ctx, userCred)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bucket.RealDelete")
|
||||
}
|
||||
@@ -379,15 +423,15 @@ func (bucket *SBucket) RemoteCreate(ctx context.Context, userCred mcclient.Token
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "iregion.CreateIBucket")
|
||||
}
|
||||
err = db.SetExternalId(bucket, userCred, bucket.Name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "db.SetExternalId")
|
||||
}
|
||||
extBucket, err := iregion.GetIBucketById(bucket.Name)
|
||||
extBucket, err := iregion.GetIBucketByName(bucket.Name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "iregion.GetIBucketByName")
|
||||
}
|
||||
err = bucket.syncWithCloudBucket(ctx, userCred, extBucket, nil)
|
||||
err = db.SetExternalId(bucket, userCred, extBucket.GetGlobalId())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "db.SetExternalId")
|
||||
}
|
||||
err = bucket.syncWithCloudBucket(ctx, userCred, extBucket, nil, false)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bucket.syncWithCloudBucket")
|
||||
}
|
||||
@@ -607,6 +651,9 @@ func (bucket *SBucket) PerformDelete(
|
||||
return ok, nil
|
||||
}
|
||||
})
|
||||
|
||||
bucket.syncWithCloudBucket(ctx, userCred, iBucket, nil, true)
|
||||
|
||||
return modules.SubmitResults2JSON(results), nil
|
||||
}
|
||||
|
||||
@@ -644,5 +691,136 @@ func (bucket *SBucket) PerformUpload(
|
||||
return nil, httperrors.NewInternalServerError("put object error %s", err)
|
||||
}
|
||||
|
||||
bucket.syncWithCloudBucket(ctx, userCred, iBucket, nil, true)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (bucket *SBucket) AllowPerformAcl(ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject,
|
||||
) bool {
|
||||
return bucket.IsOwner(userCred)
|
||||
}
|
||||
|
||||
func (bucket *SBucket) PerformAcl(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
aclStr, _ := data.GetString("acl")
|
||||
objKey, _ := data.GetString("key")
|
||||
switch cloudprovider.TBucketACLType(aclStr) {
|
||||
case cloudprovider.ACLPrivate, cloudprovider.ACLAuthRead, cloudprovider.ACLPublicRead, cloudprovider.ACLPublicReadWrite:
|
||||
// do nothing
|
||||
case cloudprovider.ACLDefault:
|
||||
if len(objKey) == 0 {
|
||||
return nil, httperrors.NewInputParameterError("invalud acl")
|
||||
}
|
||||
default:
|
||||
return nil, httperrors.NewInputParameterError("invalud acl")
|
||||
}
|
||||
|
||||
iBucket, err := bucket.GetIBucket()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("fail to find external bucket: %s", err)
|
||||
}
|
||||
|
||||
if len(objKey) == 0 {
|
||||
err = iBucket.SetAcl(cloudprovider.TBucketACLType(aclStr))
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("setAcl error %s", err)
|
||||
}
|
||||
|
||||
err = bucket.syncWithCloudBucket(ctx, userCred, iBucket, nil, false)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("syncWithCloudBucket error %s", err)
|
||||
}
|
||||
} else {
|
||||
objects, err := iBucket.GetIObjects(objKey, false)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("iBucket.GetIObjects error %s", err)
|
||||
}
|
||||
if len(objects) == 0 {
|
||||
return nil, httperrors.NewResourceNotFoundError("object %s not found", objKey)
|
||||
}
|
||||
err = objects[0].SetAcl(cloudprovider.TBucketACLType(aclStr))
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("setAcl error %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (bucket *SBucket) AllowPerformSync(ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject,
|
||||
) bool {
|
||||
return bucket.IsOwner(userCred)
|
||||
}
|
||||
|
||||
func (bucket *SBucket) PerformSync(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
data jsonutils.JSONObject,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
iBucket, err := bucket.GetIBucket()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("fail to find external bucket: %s", err)
|
||||
}
|
||||
|
||||
err = bucket.syncWithCloudBucket(ctx, userCred, iBucket, nil, false)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("syncWithCloudBucket error %s", err)
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (bucket *SBucket) ValidateDeleteCondition(ctx context.Context) error {
|
||||
if bucket.ObjectCnt > 0 {
|
||||
return httperrors.NewNotEmptyError("not an empty bucket")
|
||||
}
|
||||
return bucket.SVirtualResourceBase.ValidateDeleteCondition(ctx)
|
||||
}
|
||||
|
||||
func (bucket *SBucket) AllowGetDetailsAcl(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
) bool {
|
||||
return bucket.IsOwner(userCred)
|
||||
}
|
||||
|
||||
func (bucket *SBucket) GetDetailsAcl(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
iBucket, err := bucket.GetIBucket()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("fail to find external bucket: %s", err)
|
||||
}
|
||||
objKey, _ := query.GetString("key")
|
||||
var acl cloudprovider.TBucketACLType
|
||||
if len(objKey) == 0 {
|
||||
acl = iBucket.GetAcl()
|
||||
} else {
|
||||
objects, err := iBucket.GetIObjects(objKey, false)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("iBucket.GetIObjects error %s", err)
|
||||
}
|
||||
if len(objects) == 0 {
|
||||
return nil, httperrors.NewNotFoundError("object %s not found", objKey)
|
||||
}
|
||||
acl = objects[0].GetAcl()
|
||||
}
|
||||
ret := jsonutils.NewDict()
|
||||
ret.Add(jsonutils.NewString(string(acl)), "acl")
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -82,9 +82,13 @@ type SCloudaccount struct {
|
||||
|
||||
// BalanceKey string `width:"256" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
|
||||
|
||||
AccountId string `width:"128" charset:"utf8" nullable:"true" list:"domain" create:"domain_optional"`
|
||||
|
||||
IsPublicCloud tristate.TriState `nullable:"false" get:"user" create:"optional" list:"user" default:"true"`
|
||||
IsOnPremise bool `nullable:"false" get:"user" create:"optional" list:"user" default:"false"`
|
||||
|
||||
HasObjectStorage bool `nullable:"false" get:"user" create:"optional" list:"user" default:"false"`
|
||||
|
||||
Provider string `width:"64" charset:"ascii" list:"domain" create:"domain_required"`
|
||||
|
||||
EnableAutoSync bool `default:"false" create:"domain_optional" list:"domain"`
|
||||
@@ -297,7 +301,7 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use
|
||||
return nil, httperrors.NewConflictError("The account has been registered")
|
||||
}
|
||||
|
||||
err = cloudprovider.IsValidCloudAccount(url, account, secret, provider)
|
||||
accountId, err := cloudprovider.IsValidCloudAccount(url, account, secret, provider)
|
||||
if err != nil {
|
||||
if err == cloudprovider.ErrNoSuchProvder {
|
||||
return nil, httperrors.NewResourceNotFoundError("no such provider %s", provider)
|
||||
@@ -306,6 +310,18 @@ func (manager *SCloudaccountManager) ValidateCreateData(ctx context.Context, use
|
||||
return nil, httperrors.NewInputParameterError("invalid cloud account info error: %s", err.Error())
|
||||
}
|
||||
|
||||
// check accountId uniqueness
|
||||
if len(accountId) > 0 {
|
||||
cnt, err := manager.Query().Equals("account_id", accountId).CountWithError()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("check account_id duplication error %s", err)
|
||||
}
|
||||
if cnt > 0 {
|
||||
return nil, httperrors.NewDuplicateResourceError("the account has been registerd %s", accountId)
|
||||
}
|
||||
data.Set("account_id", jsonutils.NewString(accountId))
|
||||
}
|
||||
|
||||
syncIntervalSecs, _ := data.Int("sync_interval_seconds")
|
||||
if syncIntervalSecs == 0 {
|
||||
syncIntervalSecs = int64(options.Options.DefaultSyncIntervalSeconds)
|
||||
@@ -425,9 +441,13 @@ func (self *SCloudaccount) PerformUpdateCredential(ctx context.Context, userCred
|
||||
|
||||
originSecret, _ := self.getPassword()
|
||||
|
||||
if err := cloudprovider.IsValidCloudAccount(self.AccessUrl, account.Account, account.Secret, self.Provider); err != nil {
|
||||
accountId, err := cloudprovider.IsValidCloudAccount(self.AccessUrl, account.Account, account.Secret, self.Provider)
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInputParameterError("invalid cloud account info error: %s", err.Error())
|
||||
}
|
||||
if accountId != self.AccountId {
|
||||
return nil, httperrors.NewConflictError("inconsistent account_id, previous '%s' and now '%s'", self.AccountId, accountId)
|
||||
}
|
||||
|
||||
if (account.Account != self.Account) || (account.Secret != originSecret) {
|
||||
if account.Account != self.Account {
|
||||
@@ -1279,6 +1299,7 @@ func (account *SCloudaccount) probeAccountStatus(ctx context.Context, userCred m
|
||||
isPublic := factory.IsPublicCloud()
|
||||
account.IsPublicCloud = tristate.NewFromBool(isPublic)
|
||||
account.IsOnPremise = factory.IsOnPremise()
|
||||
account.HasObjectStorage = factory.IsSupportObjectStorage()
|
||||
account.Balance = balance
|
||||
account.HealthStatus = status
|
||||
account.ProbeAt = timeutils.UtcNow()
|
||||
|
||||
@@ -1340,3 +1340,43 @@ func (provider *SCloudprovider) GetDetailsClirc(ctx context.Context, userCred mc
|
||||
func (manager *SCloudproviderManager) ResourceScope() rbacutils.TRbacScope {
|
||||
return rbacutils.ScopeDomain
|
||||
}
|
||||
|
||||
func (provider *SCloudprovider) AllowGetDetailsStorageClasses(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
) bool {
|
||||
return db.IsAdminAllowGetSpec(userCred, provider, "storage-classes")
|
||||
}
|
||||
|
||||
func (provider *SCloudprovider) GetDetailsStorageClasses(
|
||||
ctx context.Context,
|
||||
userCred mcclient.TokenCredential,
|
||||
query jsonutils.JSONObject,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
driver, err := provider.GetProvider()
|
||||
if err != nil {
|
||||
return nil, httperrors.NewInternalServerError("fail to get provider driver %s", err)
|
||||
}
|
||||
extId := ""
|
||||
regionStr := jsonutils.GetAnyString(query, []string{"cloudregion", "cloudregion_id"})
|
||||
if len(regionStr) > 0 {
|
||||
regionObj, err := CloudregionManager.FetchByIdOrName(userCred, regionStr)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError2(CloudregionManager.Keyword(), regionStr)
|
||||
} else {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
}
|
||||
extId = regionObj.(*SCloudregion).GetExternalId()
|
||||
}
|
||||
|
||||
sc := driver.GetStorageClasses(extId)
|
||||
if sc == nil {
|
||||
return nil, httperrors.NewInternalServerError("storage classes not supported")
|
||||
}
|
||||
ret := jsonutils.NewDict()
|
||||
ret.Add(jsonutils.NewStringArray(sc), "storage_classes")
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
"github.com/pkg/errors"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
@@ -52,7 +54,12 @@ type SAliyunClient struct {
|
||||
providerName string
|
||||
accessKey string
|
||||
secret string
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
ownerId string
|
||||
ownerName string
|
||||
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
|
||||
Debug bool
|
||||
}
|
||||
@@ -67,7 +74,14 @@ func NewAliyunClient(providerId string, providerName string, accessKey string, s
|
||||
}
|
||||
err := client.fetchRegions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fetchRegions")
|
||||
}
|
||||
err = client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
if client.Debug {
|
||||
log.Debugf("ClientID: %s ClientName: %s", client.ownerId, client.ownerName)
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
@@ -183,6 +197,83 @@ func (self *SAliyunClient) fetchRegions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// oss endpoint
|
||||
// https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.6.6E8ZkO
|
||||
func getOSSExternalDomain(regionId string) string {
|
||||
return fmt.Sprintf("oss-%s.aliyuncs.com", regionId)
|
||||
}
|
||||
|
||||
func getOSSInternalDomain(regionId string) string {
|
||||
return fmt.Sprintf("oss-%s-internal.aliyuncs.com", regionId)
|
||||
}
|
||||
|
||||
// https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.6.XqEgD1
|
||||
func (client *SAliyunClient) getOssClient(regionId string) (*oss.Client, error) {
|
||||
ep := getOSSExternalDomain(regionId)
|
||||
cli, err := oss.New(ep, client.accessKey, client.secret)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "oss.New")
|
||||
}
|
||||
return cli, nil
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) getRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetId() == id {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) invalidateIBuckets() {
|
||||
self.iBuckets = nil
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if self.iBuckets == nil {
|
||||
err := self.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
return self.iBuckets, nil
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) fetchBuckets() error {
|
||||
osscli, err := self.getOssClient(ALIYUN_DEFAULT_REGION)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "self.getOssClient")
|
||||
}
|
||||
result, err := osscli.ListBuckets()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "oss.ListBuckets")
|
||||
}
|
||||
|
||||
self.ownerId = result.Owner.ID
|
||||
self.ownerName = result.Owner.DisplayName
|
||||
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for _, bInfo := range result.Buckets {
|
||||
regionId := bInfo.Location[4:]
|
||||
region, err := self.getRegionByRegionId(regionId)
|
||||
if err != nil {
|
||||
log.Errorf("cannot find bucket's region %s", regionId)
|
||||
continue
|
||||
}
|
||||
b := SBucket{
|
||||
region: region.(*SRegion),
|
||||
Name: bInfo.Name,
|
||||
Location: bInfo.Location,
|
||||
CreationDate: bInfo.CreationDate,
|
||||
StorageClass: bInfo.StorageClass,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
}
|
||||
self.iBuckets = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) GetRegions() []SRegion {
|
||||
regions := make([]SRegion, len(self.iregions))
|
||||
for i := 0; i < len(regions); i += 1 {
|
||||
@@ -204,6 +295,10 @@ func (self *SAliyunClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error)
|
||||
return []cloudprovider.SSubAccount{subAccount}, nil
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) GetAccountId() string {
|
||||
return self.ownerId
|
||||
}
|
||||
|
||||
func (self *SAliyunClient) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.iregions
|
||||
}
|
||||
|
||||
@@ -20,24 +20,24 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
|
||||
"github.com/aliyun/aliyun-oss-go-sdk/oss"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
)
|
||||
|
||||
type SBucket struct {
|
||||
objectstore.SBucket
|
||||
multicloud.SBaseBucket
|
||||
|
||||
region *SRegion
|
||||
|
||||
Name string
|
||||
Location string
|
||||
CreationDate time.Time
|
||||
StorageClass string
|
||||
Acl string
|
||||
}
|
||||
|
||||
func (b *SBucket) GetProjectId() string {
|
||||
@@ -52,8 +52,20 @@ func (b *SBucket) GetName() string {
|
||||
return b.Name
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() string {
|
||||
return b.Acl
|
||||
func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLPrivate
|
||||
osscli, err := b.region.GetOssClient()
|
||||
if err != nil {
|
||||
log.Errorf("b.region.GetOssClient fail %s", err)
|
||||
return acl
|
||||
}
|
||||
aclResp, err := osscli.GetBucketACL(b.Name)
|
||||
if err != nil {
|
||||
log.Errorf("osscli.GetBucketACL fail %s", err)
|
||||
return acl
|
||||
}
|
||||
acl = cloudprovider.TBucketACLType(aclResp.ACL)
|
||||
return acl
|
||||
}
|
||||
|
||||
func (b *SBucket) GetLocation() string {
|
||||
@@ -75,16 +87,41 @@ func (b *SBucket) GetStorageClass() string {
|
||||
func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
return []cloudprovider.SBucketAccessUrl{
|
||||
{
|
||||
Url: fmt.Sprintf("https://%s.aliyuncs.com", b.Location),
|
||||
Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()),
|
||||
Description: "ExtranetEndpoint",
|
||||
},
|
||||
{
|
||||
Url: fmt.Sprintf("https://%s-internal.aliyuncs.com", b.Location),
|
||||
Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSInternalDomain()),
|
||||
Description: "IntranetEndpoint",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SBucket) GetStats() cloudprovider.SBucketStats {
|
||||
stats, err := cloudprovider.GetIBucketStats(b)
|
||||
if err != nil {
|
||||
log.Errorf("GetStats fail %s", err)
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
osscli, err := b.region.GetOssClient()
|
||||
if err != nil {
|
||||
log.Errorf("b.region.GetOssClient fail %s", err)
|
||||
return errors.Wrap(err, "b.region.GetOssClient")
|
||||
}
|
||||
acl, err := str2Acl(string(aclStr))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "str2Acl")
|
||||
}
|
||||
err = osscli.SetBucketACL(b.Name, acl)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetBucketACL")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) {
|
||||
result := cloudprovider.SListObjectResult{}
|
||||
osscli, err := b.region.GetOssClient()
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
package aliyun
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
@@ -27,3 +30,44 @@ type SObject struct {
|
||||
func (o *SObject) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return o.bucket
|
||||
}
|
||||
|
||||
func (o *SObject) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLDefault
|
||||
osscli, err := o.bucket.region.GetOssClient()
|
||||
if err != nil {
|
||||
log.Errorf("o.bucket.region.GetOssClient error %s", err)
|
||||
return acl
|
||||
}
|
||||
bucket, err := osscli.Bucket(o.bucket.Name)
|
||||
if err != nil {
|
||||
log.Errorf("osscli.Bucket error %s", err)
|
||||
return acl
|
||||
}
|
||||
result, err := bucket.GetObjectACL(o.Key)
|
||||
if err != nil {
|
||||
log.Errorf("bucket.GetObjectACL error %s", err)
|
||||
return acl
|
||||
}
|
||||
acl = cloudprovider.TBucketACLType(result.ACL)
|
||||
return acl
|
||||
}
|
||||
|
||||
func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
acl, err := str2Acl(string(aclStr))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "str2Acl")
|
||||
}
|
||||
osscli, err := o.bucket.region.GetOssClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "o.bucket.region.GetOssClient")
|
||||
}
|
||||
bucket, err := osscli.Bucket(o.bucket.Name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "osscli.Bucket")
|
||||
}
|
||||
err = bucket.SetObjectACL(o.Key, acl)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bucket.SetObjectACL")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -114,6 +114,10 @@ func (self *SAliyunProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SAliyunProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SAliyunProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -139,3 +143,9 @@ func (self *SAliyunProvider) GetBalance() (float64, string, error) {
|
||||
func (self *SAliyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SAliyunProvider) GetStorageClasses(regionId string) []string {
|
||||
return []string{
|
||||
"Standard", "IA", "Archive",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,23 +84,19 @@ func (self *SRegion) getSdkClient() (*sdk.Client, error) {
|
||||
return self.sdkClient, nil
|
||||
}
|
||||
|
||||
// oss endpoint
|
||||
// https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.6.6E8ZkO
|
||||
func (self *SRegion) GetOSSExternalDomain() string {
|
||||
return fmt.Sprintf("oss-%s.aliyuncs.com", self.RegionId)
|
||||
func (self *SRegion) getOSSExternalDomain() string {
|
||||
return getOSSExternalDomain(self.RegionId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetOSSInternalDomain() string {
|
||||
return fmt.Sprintf("oss-%s-internal.aliyuncs.com", self.RegionId)
|
||||
func (self *SRegion) getOSSInternalDomain() string {
|
||||
return getOSSInternalDomain(self.RegionId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetOssClient() (*oss.Client, error) {
|
||||
if self.ossClient == nil {
|
||||
// https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.6.XqEgD1
|
||||
ep := self.GetOSSExternalDomain()
|
||||
cli, err := oss.New(ep, self.client.accessKey, self.client.secret)
|
||||
cli, err := self.client.getOssClient(self.RegionId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "self.client.getOssClient")
|
||||
}
|
||||
self.ossClient = cli
|
||||
}
|
||||
@@ -940,35 +936,18 @@ func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAc
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
osscli, err := region.GetOssClient()
|
||||
iBuckets, err := region.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.GetOssClient")
|
||||
return nil, errors.Wrap(err, "getIBuckets")
|
||||
}
|
||||
result, err := osscli.ListBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "oss.ListBuckets")
|
||||
}
|
||||
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for _, bInfo := range result.Buckets {
|
||||
if bInfo.Location[4:] != region.GetId() {
|
||||
for i := range iBuckets {
|
||||
loc := iBuckets[i].GetLocation()
|
||||
// remove oss- prefix
|
||||
if loc[4:] != region.GetId() {
|
||||
continue
|
||||
}
|
||||
acl := string(oss.ACLPrivate)
|
||||
aclResp, err := osscli.GetBucketACL(bInfo.Name)
|
||||
if err == nil {
|
||||
acl = aclResp.ACL
|
||||
}
|
||||
b := SBucket{
|
||||
region: region,
|
||||
|
||||
Name: bInfo.Name,
|
||||
Location: bInfo.Location,
|
||||
CreationDate: bInfo.CreationDate,
|
||||
StorageClass: bInfo.StorageClass,
|
||||
Acl: acl,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
ret = append(ret, iBuckets[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -1025,6 +1004,7 @@ func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "oss.CreateBucket")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1050,6 +1030,7 @@ func (region *SRegion) DeleteIBucket(name string) error {
|
||||
}
|
||||
return errors.Wrap(err, "DeleteBucket")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1081,11 +1062,14 @@ func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket,
|
||||
Location: bInfo.Location,
|
||||
CreationDate: bInfo.CreationDate,
|
||||
StorageClass: bInfo.StorageClass,
|
||||
Acl: bInfo.ACL,
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return region.GetIBucketById(name)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) {
|
||||
caches, err := self.GetElasticCaches(nil)
|
||||
if err != nil {
|
||||
|
||||
+110
-10
@@ -23,7 +23,9 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
@@ -40,7 +42,9 @@ const (
|
||||
AWS_API_VERSION = "2018-10-10"
|
||||
)
|
||||
|
||||
var DEBUG bool = false
|
||||
var (
|
||||
DEBUG = false
|
||||
)
|
||||
|
||||
type SAwsClient struct {
|
||||
providerId string
|
||||
@@ -48,7 +52,12 @@ type SAwsClient struct {
|
||||
accessUrl string // 服务区域 ChinaCloud | InternationalCloud
|
||||
accessKey string
|
||||
secret string
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
ownerId string
|
||||
ownerName string
|
||||
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
|
||||
debug bool
|
||||
}
|
||||
@@ -60,12 +69,19 @@ func NewAwsClient(providerId string, providerName string, accessUrl string, acce
|
||||
accessUrl: accessUrl,
|
||||
accessKey: accessKey,
|
||||
secret: secret,
|
||||
debug: debug,
|
||||
}
|
||||
DEBUG = debug
|
||||
err := client.fetchRegions()
|
||||
if err != nil {
|
||||
log.Debugf("NewAwsClient %s", err.Error())
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fetchRegions")
|
||||
}
|
||||
err = client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
if debug {
|
||||
log.Debugf("ownerId: %s ownerName: %s", client.ownerId, client.ownerName)
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
@@ -86,12 +102,8 @@ func (self *SAwsClient) getDefaultRegionId() string {
|
||||
return GetDefaultRegionId(self.accessUrl)
|
||||
}
|
||||
|
||||
func (self *SAwsClient) getDefaultSession() (*session.Session, error) {
|
||||
defaultRegion := self.getDefaultRegionId()
|
||||
return session.NewSession(&sdk.Config{
|
||||
Region: sdk.String(defaultRegion),
|
||||
Credentials: credentials.NewStaticCredentials(self.accessKey, self.secret, ""),
|
||||
})
|
||||
func (client *SAwsClient) getDefaultSession() (*session.Session, error) {
|
||||
return client.getAwsSession(client.getDefaultRegionId())
|
||||
}
|
||||
|
||||
func (self *SAwsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
@@ -107,6 +119,10 @@ func (self *SAwsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
return []cloudprovider.SSubAccount{subAccount}, nil
|
||||
}
|
||||
|
||||
func (client *SAwsClient) GetAccountId() string {
|
||||
return client.ownerId
|
||||
}
|
||||
|
||||
func (self *SAwsClient) UpdateAccount(accessKey, secret string) error {
|
||||
if self.accessKey != accessKey || self.secret != secret {
|
||||
self.accessKey = accessKey
|
||||
@@ -149,6 +165,81 @@ func (self *SAwsClient) fetchRegions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *SAwsClient) getAwsSession(regionId string) (*session.Session, error) {
|
||||
disableParamValidation := true
|
||||
chainVerboseErrors := true
|
||||
return session.NewSession(&sdk.Config{
|
||||
Region: sdk.String(regionId),
|
||||
Credentials: credentials.NewStaticCredentials(client.accessKey, client.secret, ""),
|
||||
DisableParamValidation: &disableParamValidation,
|
||||
|
||||
CredentialsChainVerboseErrors: &chainVerboseErrors,
|
||||
})
|
||||
}
|
||||
|
||||
func (self *SAwsClient) invalidateIBuckets() {
|
||||
self.iBuckets = nil
|
||||
}
|
||||
|
||||
func (self *SAwsClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if self.iBuckets == nil {
|
||||
err := self.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
return self.iBuckets, nil
|
||||
}
|
||||
|
||||
func (client *SAwsClient) fetchBuckets() error {
|
||||
s, err := client.getDefaultSession()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getDefaultSession")
|
||||
}
|
||||
s3cli := s3.New(s)
|
||||
output, err := s3cli.ListBuckets(&s3.ListBucketsInput{})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "ListBuckets")
|
||||
}
|
||||
|
||||
if output.Owner != nil {
|
||||
if output.Owner.ID != nil {
|
||||
client.ownerId = *output.Owner.ID
|
||||
}
|
||||
if output.Owner.DisplayName != nil {
|
||||
client.ownerName = *output.Owner.DisplayName
|
||||
}
|
||||
}
|
||||
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for _, bInfo := range output.Buckets {
|
||||
input := &s3.GetBucketLocationInput{}
|
||||
input.Bucket = bInfo.Name
|
||||
output, err := s3cli.GetBucketLocation(input)
|
||||
if err != nil {
|
||||
log.Errorf("s3cli.GetBucketLocation error %s", err)
|
||||
continue
|
||||
}
|
||||
location := *output.LocationConstraint
|
||||
region, err := client.getIRegionByRegionId(location)
|
||||
if err != nil {
|
||||
log.Errorf("client.getIRegionByRegionId %s fail %s", location, err)
|
||||
continue
|
||||
}
|
||||
b := SBucket{
|
||||
region: region.(*SRegion),
|
||||
Name: *bInfo.Name,
|
||||
Location: location,
|
||||
CreationDate: *bInfo.CreationDate,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
}
|
||||
|
||||
client.iBuckets = ret
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 只是使用fetchRegions初始化好的self.iregions. 本身并不从云服务器厂商拉取region信息
|
||||
func (self *SAwsClient) GetRegions() []SRegion {
|
||||
regions := make([]SRegion, len(self.iregions))
|
||||
@@ -181,6 +272,15 @@ func (self *SAwsClient) GetRegion(regionId string) *SRegion {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SAwsClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetId() == id {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, ErrorNotFound()
|
||||
}
|
||||
|
||||
func (self *SAwsClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetGlobalId() == id {
|
||||
|
||||
@@ -22,23 +22,27 @@ import (
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/minio-go"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
)
|
||||
|
||||
type SBucket struct {
|
||||
objectstore.SBucket
|
||||
multicloud.SBaseBucket
|
||||
|
||||
region *SRegion
|
||||
|
||||
Name string
|
||||
Location string
|
||||
CreationDate time.Time
|
||||
Location string
|
||||
|
||||
acl cloudprovider.TBucketACLType
|
||||
}
|
||||
|
||||
func (b *SBucket) GetProjectId() string {
|
||||
@@ -69,8 +73,61 @@ func (b *SBucket) GetStorageClass() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() string {
|
||||
return ""
|
||||
func s3ToCannedAcl(acls []*s3.Grant) cloudprovider.TBucketACLType {
|
||||
switch {
|
||||
case len(acls) == 1:
|
||||
if acls[0].Grantee.URI == nil && *acls[0].Permission == minio.PERMISSION_FULL_CONTROL {
|
||||
return cloudprovider.ACLPrivate
|
||||
}
|
||||
case len(acls) == 2:
|
||||
for _, g := range acls {
|
||||
if *g.Grantee.Type == minio.GRANTEE_TYPE_GROUP && *g.Grantee.URI == minio.GRANTEE_GROUP_URI_AUTH_USERS && *g.Permission == minio.PERMISSION_READ {
|
||||
return cloudprovider.ACLAuthRead
|
||||
}
|
||||
if *g.Grantee.Type == minio.GRANTEE_TYPE_GROUP && *g.Grantee.URI == minio.GRANTEE_GROUP_URI_ALL_USERS && *g.Permission == minio.PERMISSION_READ {
|
||||
return cloudprovider.ACLPublicRead
|
||||
}
|
||||
}
|
||||
case len(acls) == 3:
|
||||
for _, g := range acls {
|
||||
if *g.Grantee.Type == minio.GRANTEE_TYPE_GROUP && *g.Grantee.URI == minio.GRANTEE_GROUP_URI_ALL_USERS && *g.Permission == minio.PERMISSION_WRITE {
|
||||
return cloudprovider.ACLPublicReadWrite
|
||||
}
|
||||
}
|
||||
}
|
||||
return cloudprovider.ACLUnknown
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLPrivate
|
||||
s3cli, err := b.region.GetS3Client()
|
||||
if err != nil {
|
||||
log.Errorf("b.region.GetS3Client fail %s", err)
|
||||
return acl
|
||||
}
|
||||
input := &s3.GetBucketAclInput{}
|
||||
input.SetBucket(b.Name)
|
||||
output, err := s3cli.GetBucketAcl(input)
|
||||
if err != nil {
|
||||
log.Errorf("s3cli.GetBucketAcl fail %s", err)
|
||||
return acl
|
||||
}
|
||||
return s3ToCannedAcl(output.Grants)
|
||||
}
|
||||
|
||||
func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
s3cli, err := b.region.GetS3Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "b.region.GetS3Client")
|
||||
}
|
||||
input := &s3.PutBucketAclInput{}
|
||||
input.SetBucket(b.Name)
|
||||
input.SetACL(string(aclStr))
|
||||
_, err = s3cli.PutBucketAcl(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "PutBucketAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
@@ -86,6 +143,11 @@ func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SBucket) GetStats() cloudprovider.SBucketStats {
|
||||
stats, _ := cloudprovider.GetIBucketStats(b)
|
||||
return stats
|
||||
}
|
||||
|
||||
func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) {
|
||||
result := cloudprovider.SListObjectResult{}
|
||||
s3cli, err := b.region.GetS3Client()
|
||||
@@ -148,7 +210,7 @@ func (b *SBucket) GetIObjects(prefix string, isRecursive bool) ([]cloudprovider.
|
||||
}
|
||||
|
||||
func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, contType string, storageClassStr string) error {
|
||||
sess, err := session.NewSession(&aws.Config{Region: aws.String(b.region.GetId())})
|
||||
sess, err := b.region.getAwsSession()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "session.NewSession")
|
||||
}
|
||||
|
||||
@@ -111,6 +111,10 @@ func (self *SAwsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error)
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SAwsProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SAwsProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -138,3 +142,14 @@ func (self *SAwsProvider) GetBalance() (float64, string, error) {
|
||||
func (self *SAwsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SAwsProvider) GetStorageClasses(regionId string) []string {
|
||||
return []string{
|
||||
"STANDARD",
|
||||
"STANDARD_IA",
|
||||
"ONEZONE_IA",
|
||||
"GLACIER",
|
||||
"DEEP_ARCHIVE",
|
||||
"INTELLIGENT_TIERING",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,16 +23,14 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
|
||||
sdk "github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/client"
|
||||
"github.com/aws/aws-sdk-go/aws/client/metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
v4 "github.com/aws/aws-sdk-go/aws/signer/v4"
|
||||
"github.com/aws/aws-sdk-go/private/protocol/query"
|
||||
"github.com/aws/aws-sdk-go/service/acm"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/aws/aws-sdk-go/service/elbv2"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
@@ -42,7 +40,6 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/acm"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
@@ -105,12 +102,7 @@ func (self *SRegion) GetClient() *SAwsClient {
|
||||
}
|
||||
|
||||
func (self *SRegion) getAwsSession() (*session.Session, error) {
|
||||
disableParamValidation := true
|
||||
return session.NewSession(&sdk.Config{
|
||||
Region: sdk.String(self.RegionId),
|
||||
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
|
||||
DisableParamValidation: &disableParamValidation,
|
||||
})
|
||||
return self.client.getAwsSession(self.RegionId)
|
||||
}
|
||||
|
||||
func (self *SRegion) getEc2Client() (*ec2.EC2, error) {
|
||||
@@ -145,14 +137,11 @@ func (self *SRegion) getIamClient() (*iam.IAM, error) {
|
||||
func (self *SRegion) GetS3Client() (*s3.S3, error) {
|
||||
if self.s3Client == nil {
|
||||
s, err := self.getAwsSession()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
self.s3Client = s3.New(s)
|
||||
}
|
||||
|
||||
return self.s3Client, nil
|
||||
}
|
||||
|
||||
@@ -273,7 +262,7 @@ func (self *SRegion) rdsRequest(apiName string, params map[string]string, retval
|
||||
APIVersion: "2014-10-31",
|
||||
}
|
||||
|
||||
if DEBUG {
|
||||
if self.client.debug {
|
||||
logLevel := aws.LogLevelType(uint(aws.LogDebugWithRequestErrors) + uint(aws.LogDebugWithHTTPBody))
|
||||
c.Config.LogLevel = &logLevel
|
||||
}
|
||||
@@ -880,33 +869,16 @@ func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalanc
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
s3cli, err := region.GetS3Client()
|
||||
iBuckets, err := region.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetS3Client")
|
||||
}
|
||||
output, err := s3cli.ListBuckets(&s3.ListBucketsInput{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ListBuckets")
|
||||
return nil, errors.Wrap(err, "getIBuckets")
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for _, bInfo := range output.Buckets {
|
||||
input := &s3.GetBucketLocationInput{}
|
||||
input.Bucket = bInfo.Name
|
||||
output, err := s3cli.GetBucketLocation(input)
|
||||
if err != nil {
|
||||
log.Errorf("s3cli.GetBucketLocation error %s", err)
|
||||
for i := range iBuckets {
|
||||
if iBuckets[i].GetLocation() != region.GetId() {
|
||||
continue
|
||||
}
|
||||
if *output.LocationConstraint != region.GetId() {
|
||||
continue
|
||||
}
|
||||
b := SBucket{
|
||||
region: region,
|
||||
Name: *bInfo.Name,
|
||||
Location: region.GetId(),
|
||||
CreationDate: *bInfo.CreationDate,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
ret = append(ret, iBuckets[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -917,14 +889,14 @@ func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl st
|
||||
return errors.Wrap(err, "GetS3Client")
|
||||
}
|
||||
input := &s3.CreateBucketInput{}
|
||||
input.Bucket = &name
|
||||
input.SetBucket(name)
|
||||
input.CreateBucketConfiguration = &s3.CreateBucketConfiguration{}
|
||||
location := region.GetId()
|
||||
input.CreateBucketConfiguration.LocationConstraint = &location
|
||||
input.CreateBucketConfiguration.SetLocationConstraint(region.GetId())
|
||||
_, err = s3cli.CreateBucket(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "CreateBucket")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
// if *output.Location != region.GetId() {
|
||||
// log.Warningf("Request location %s != got locaiton %s", region.GetId(), *output.Location)
|
||||
// }
|
||||
@@ -945,6 +917,7 @@ func (region *SRegion) DeleteIBucket(name string) error {
|
||||
}
|
||||
return errors.Wrap(err, "DeleteBucket")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -966,6 +939,10 @@ func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket,
|
||||
return cloudprovider.GetIBucketById(region, name)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return region.GetIBucketById(name)
|
||||
}
|
||||
|
||||
func (region *SRegion) getBaseEndpoint() string {
|
||||
if len(region.RegionEndpoint) > 4 {
|
||||
return region.RegionEndpoint[4:]
|
||||
|
||||
@@ -14,7 +14,14 @@
|
||||
|
||||
package aws
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SObject struct {
|
||||
bucket *SBucket
|
||||
@@ -25,3 +32,37 @@ type SObject struct {
|
||||
func (o *SObject) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return o.bucket
|
||||
}
|
||||
|
||||
func (o *SObject) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLDefault
|
||||
s3cli, err := o.bucket.region.GetS3Client()
|
||||
if err != nil {
|
||||
log.Errorf("o.bucket.region.GetS3Client error %s", err)
|
||||
return acl
|
||||
}
|
||||
input := &s3.GetObjectAclInput{}
|
||||
input.SetBucket(o.bucket.Name)
|
||||
input.SetKey(o.Key)
|
||||
output, err := s3cli.GetObjectAcl(input)
|
||||
if err != nil {
|
||||
log.Errorf("s3cli.GetObjectAcl error %s", err)
|
||||
return acl
|
||||
}
|
||||
return s3ToCannedAcl(output.Grants)
|
||||
}
|
||||
|
||||
func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
s3cli, err := o.bucket.region.GetS3Client()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "o.bucket.region.GetS3Client")
|
||||
}
|
||||
input := &s3.PutObjectAclInput{}
|
||||
input.SetBucket(o.bucket.Name)
|
||||
input.SetKey(o.Key)
|
||||
input.SetACL(string(aclStr))
|
||||
_, err = s3cli.PutObjectAcl(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "s3cli.PutObjectAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
// "yunion.io/x/onecloud/pkg/httperrors"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -57,7 +57,9 @@ type SAzureClient struct {
|
||||
fetchResourceGroups bool
|
||||
env azureenv.Environment
|
||||
authorizer autorest.Authorizer
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
|
||||
debug bool
|
||||
}
|
||||
@@ -100,7 +102,11 @@ func NewAzureClient(providerId string, providerName string, envName, tenantId, c
|
||||
}
|
||||
err := client.fetchRegions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fetchRegions")
|
||||
}
|
||||
err = client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
@@ -709,6 +715,41 @@ func (self *SAzureClient) fetchRegions() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SAzureClient) invalidateIBuckets() {
|
||||
self.iBuckets = nil
|
||||
}
|
||||
|
||||
func (self *SAzureClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if self.iBuckets == nil {
|
||||
err := self.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
return self.iBuckets, nil
|
||||
}
|
||||
|
||||
func (client *SAzureClient) fetchBuckets() error {
|
||||
accounts := []SStorageAccount{}
|
||||
err := client.ListAll("Microsoft.Storage/storageAccounts", &accounts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "client.ListAll")
|
||||
}
|
||||
buckets := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range accounts {
|
||||
log.Debugf("%s %s %#v", jsonutils.Marshal(accounts[i]), accounts[i].Location, accounts[i])
|
||||
region, err := client.getIRegionByRegionId(accounts[i].Location)
|
||||
if err != nil {
|
||||
log.Errorf("fail to find region '%s'", accounts[i].Location)
|
||||
continue
|
||||
}
|
||||
accounts[i].region = region.(*SRegion)
|
||||
buckets = append(buckets, &accounts[i])
|
||||
}
|
||||
client.iBuckets = buckets
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SAzureClient) GetRegions() []SRegion {
|
||||
regions := make([]SRegion, len(self.iregions))
|
||||
for i := 0; i < len(regions); i += 1 {
|
||||
@@ -748,6 +789,10 @@ func (self *SAzureClient) GetSubAccounts() (subAccounts []cloudprovider.SSubAcco
|
||||
return subAccounts, nil
|
||||
}
|
||||
|
||||
func (self *SAzureClient) GetAccountId() string {
|
||||
return self.tenantId
|
||||
}
|
||||
|
||||
func (self *SAzureClient) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.iregions
|
||||
}
|
||||
@@ -759,6 +804,15 @@ func (self *SAzureClient) getDefaultRegion() (cloudprovider.ICloudRegion, error)
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SAzureClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetId() == id {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SAzureClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetGlobalId() == id {
|
||||
@@ -848,3 +902,19 @@ func (self *SAzureClient) GetIProjects() ([]cloudprovider.ICloudProject, error)
|
||||
}
|
||||
return iprojects, nil
|
||||
}
|
||||
|
||||
func (self *SAzureClient) GetStorageClasses(regionId string) ([]string, error) {
|
||||
iRegion, err := self.GetIRegionById(regionId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getDefaultRegion")
|
||||
}
|
||||
skus, err := iRegion.(*SRegion).GetStorageAccountSkus()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetStorageAccountSkus")
|
||||
}
|
||||
ret := make([]string, 0)
|
||||
for i := range skus {
|
||||
ret = append(ret, skus[i].Name)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
package azure
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SObject struct {
|
||||
container *SContainer
|
||||
@@ -25,3 +27,11 @@ type SObject struct {
|
||||
func (o *SObject) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return o.container.storageaccount
|
||||
}
|
||||
|
||||
func (o *SObject) GetAcl() cloudprovider.TBucketACLType {
|
||||
return cloudprovider.ACLDefault
|
||||
}
|
||||
|
||||
func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ type SClassicDisk struct {
|
||||
StorageAccount SubResource
|
||||
}
|
||||
|
||||
func (self *SRegion) GetStorageAccountsDisksWithSnapshots(storageaccounts ...SStorageAccount) ([]SClassicDisk, []SClassicSnapshot, error) {
|
||||
func (self *SRegion) GetStorageAccountsDisksWithSnapshots(storageaccounts ...*SStorageAccount) ([]SClassicDisk, []SClassicSnapshot, error) {
|
||||
disks, snapshots := []SClassicDisk{}, []SClassicSnapshot{}
|
||||
for i := 0; i < len(storageaccounts); i++ {
|
||||
_disks, _snapshots, err := self.GetStorageAccountDisksWithSnapshots(storageaccounts[i])
|
||||
@@ -60,7 +60,7 @@ func (self *SRegion) GetStorageAccountsDisksWithSnapshots(storageaccounts ...SSt
|
||||
return disks, snapshots, nil
|
||||
}
|
||||
|
||||
func (self *SRegion) GetStorageAccountDisksWithSnapshots(storageaccount SStorageAccount) ([]SClassicDisk, []SClassicSnapshot, error) {
|
||||
func (self *SRegion) GetStorageAccountDisksWithSnapshots(storageaccount *SStorageAccount) ([]SClassicDisk, []SClassicSnapshot, error) {
|
||||
disks, snapshots := []SClassicDisk{}, []SClassicSnapshot{}
|
||||
containers, err := storageaccount.GetContainers()
|
||||
if err != nil {
|
||||
|
||||
@@ -96,7 +96,7 @@ func (self *SClassicStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDi
|
||||
|
||||
func (self *SClassicStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
|
||||
storageaccount, err := self.zone.region.GetStorageAccountDetail(self.ID)
|
||||
disks, _, err := self.zone.region.GetStorageAccountDisksWithSnapshots(*storageaccount)
|
||||
disks, _, err := self.zone.region.GetStorageAccountDisksWithSnapshots(storageaccount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"yunion.io/x/log"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
@@ -151,6 +152,10 @@ func (self *SAzureProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SAzureProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SAzureProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -166,3 +171,12 @@ func (self *SAzureProvider) GetBalance() (float64, string, error) {
|
||||
func (self *SAzureProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SAzureProvider) GetStorageClasses(regionId string) []string {
|
||||
sc, err := self.client.GetStorageClasses(regionId)
|
||||
if err != nil {
|
||||
log.Errorf("Fail to find storage classes")
|
||||
return nil
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -615,13 +615,16 @@ func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAc
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
accounts, err := region.GetStorageAccounts()
|
||||
iBuckets, err := region.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.GetStorageAccounts")
|
||||
return nil, errors.Wrap(err, "getIBuckets")
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, len(accounts))
|
||||
for i := range accounts {
|
||||
ret[i] = &accounts[i]
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range iBuckets {
|
||||
if iBuckets[i].GetLocation() != region.GetId() {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, iBuckets[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -648,6 +651,7 @@ func (region *SRegion) DeleteIBucket(name string) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -658,3 +662,7 @@ func (region *SRegion) IBucketExist(name string) (bool, error) {
|
||||
func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return cloudprovider.GetIBucketById(region, name)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return region.GetIBucketById(name)
|
||||
}
|
||||
|
||||
@@ -23,17 +23,17 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/storage"
|
||||
"github.com/Microsoft/azure-vhd-utils/vhdcore/common"
|
||||
"github.com/Microsoft/azure-vhd-utils/vhdcore/diskstream"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
)
|
||||
|
||||
type SContainer struct {
|
||||
@@ -79,35 +79,37 @@ type AccountProperties struct {
|
||||
}
|
||||
|
||||
type SStorageAccount struct {
|
||||
objectstore.SBucket
|
||||
multicloud.SBaseBucket
|
||||
|
||||
region *SRegion
|
||||
|
||||
accountKey string
|
||||
Sku SSku `json:"sku,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
Identity *Identity
|
||||
Properties AccountProperties
|
||||
Location string
|
||||
ID string
|
||||
Name string
|
||||
Type string
|
||||
Tags map[string]string
|
||||
|
||||
Sku SSku `json:"sku,omitempty"`
|
||||
Kind string `json:"kind,omitempty"`
|
||||
Identity *Identity
|
||||
Location string `json:"location,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Tags map[string]string
|
||||
|
||||
Properties AccountProperties `json:"properties"`
|
||||
}
|
||||
|
||||
func (self *SRegion) GetStorageAccounts() ([]SStorageAccount, error) {
|
||||
result := []SStorageAccount{}
|
||||
accounts := []SStorageAccount{}
|
||||
err := self.client.ListAll("Microsoft.Storage/storageAccounts", &accounts)
|
||||
func (self *SRegion) GetStorageAccounts() ([]*SStorageAccount, error) {
|
||||
iBuckets, err := self.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "getIBuckets")
|
||||
}
|
||||
for i := 0; i < len(accounts); i++ {
|
||||
if accounts[i].Location == self.Name {
|
||||
accounts[i].region = self
|
||||
result = append(result, accounts[i])
|
||||
ret := make([]*SStorageAccount, 0)
|
||||
for i := range iBuckets {
|
||||
if iBuckets[i].GetLocation() != self.GetId() {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, iBuckets[i].(*SStorageAccount))
|
||||
}
|
||||
return result, nil
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func randomString(prefix string, length int) string {
|
||||
@@ -244,6 +246,7 @@ func (self *SRegion) createStorageAccount(name string, skuName string) (*SStorag
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Create")
|
||||
}
|
||||
self.client.invalidateIBuckets()
|
||||
return &stoargeaccount, nil
|
||||
}
|
||||
|
||||
@@ -283,7 +286,7 @@ func (self *SRegion) getStorageAccountID(storageAccount string) (*SStorageAccoun
|
||||
for k, v := range accounts[i].Tags {
|
||||
if k == "id" && v == storageAccount {
|
||||
accounts[i].region = self
|
||||
return &accounts[i], nil
|
||||
return accounts[i], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,9 +333,9 @@ func (self *SRegion) DeleteStorageAccount(accountId string) error {
|
||||
return self.client.Delete(accountId)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetClassicStorageAccounts() ([]SStorageAccount, error) {
|
||||
result := []SStorageAccount{}
|
||||
accounts := []SStorageAccount{}
|
||||
func (self *SRegion) GetClassicStorageAccounts() ([]*SStorageAccount, error) {
|
||||
result := make([]*SStorageAccount, 0)
|
||||
accounts := make([]SStorageAccount, 0)
|
||||
err := self.client.ListAll("Microsoft.ClassicStorage/storageAccounts", &accounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -340,7 +343,7 @@ func (self *SRegion) GetClassicStorageAccounts() ([]SStorageAccount, error) {
|
||||
for i := 0; i < len(accounts); i++ {
|
||||
if accounts[i].Location == self.Name {
|
||||
accounts[i].region = self
|
||||
result = append(result, accounts[i])
|
||||
result = append(result, &accounts[i])
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
@@ -366,7 +369,7 @@ func (self *SStorageAccount) GetBlobBaseUrl() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SStorageAccount) CreateContainer(containerName string) (*SContainer, error) {
|
||||
func (self *SStorageAccount) getBlobServiceClient() (*storage.BlobStorageClient, error) {
|
||||
accessKey, err := self.GetAccountKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -375,30 +378,37 @@ func (self *SStorageAccount) CreateContainer(containerName string) (*SContainer,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
container := SContainer{storageaccount: self}
|
||||
blobService := client.GetBlobService()
|
||||
srv := client.GetBlobService()
|
||||
return &srv, nil
|
||||
}
|
||||
|
||||
func (self *SStorageAccount) CreateContainer(containerName string) (*SContainer, error) {
|
||||
blobService, err := self.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
containerRef := blobService.GetContainerReference(containerName)
|
||||
err = containerRef.Create(&storage.CreateContainerOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "Create")
|
||||
}
|
||||
return &container, jsonutils.Update(&container, containerRef)
|
||||
container := SContainer{
|
||||
storageaccount: self,
|
||||
Name: containerName,
|
||||
}
|
||||
return &container, nil
|
||||
}
|
||||
|
||||
func (self *SStorageAccount) GetContainers() ([]SContainer, error) {
|
||||
accessKey, err := self.GetAccountKey()
|
||||
blobService, err := self.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
result, err := blobService.ListContainers(storage.ListContainersParameters{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containers := []SContainer{}
|
||||
client, err := storage.NewBasicClientOnSovereignCloud(self.Name, accessKey, self.region.client.env)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := client.GetBlobService().ListContainers(storage.ListContainersParameters{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = jsonutils.Update(&containers, result.Containers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -444,12 +454,10 @@ func (self *SContainer) ListAllFiles(include *storage.IncludeBlobDataset) ([]sto
|
||||
|
||||
func (self *SContainer) ListFiles(prefix string, marker string, delimiter string, maxCount int, include *storage.IncludeBlobDataset) (storage.BlobListResponse, error) {
|
||||
var result storage.BlobListResponse
|
||||
storageaccount := self.storageaccount
|
||||
client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env)
|
||||
blobService, err := self.storageaccount.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return result, err
|
||||
return result, errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
blobService := client.GetBlobService()
|
||||
params := storage.ListBlobsParameters{Include: include}
|
||||
if len(prefix) > 0 {
|
||||
params.Prefix = prefix
|
||||
@@ -470,17 +478,11 @@ func (self *SContainer) ListFiles(prefix string, marker string, delimiter string
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (self *SContainer) getClient() (storage.Client, error) {
|
||||
storageaccount := self.storageaccount
|
||||
return storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env)
|
||||
}
|
||||
|
||||
func (self *SContainer) getContainerRef() (*storage.Container, error) {
|
||||
client, err := self.getClient()
|
||||
blobService, err := self.storageaccount.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
blobService := client.GetBlobService()
|
||||
return blobService.GetContainerReference(self.Name), nil
|
||||
}
|
||||
|
||||
@@ -512,12 +514,10 @@ func (self *SContainer) CopySnapshot(snapshotId, fileName string) (*storage.Blob
|
||||
}
|
||||
|
||||
func (self *SContainer) UploadStream(key string, reader io.Reader, contType string) error {
|
||||
storageaccount := self.storageaccount
|
||||
client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env)
|
||||
blobService, err := self.storageaccount.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "NewBasicClientOnSovereignCloud")
|
||||
return errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
blobService := client.GetBlobService()
|
||||
containerRef := blobService.GetContainerReference(self.Name)
|
||||
blobRef := containerRef.GetBlobReference(key)
|
||||
blobRef.Properties.BlobType = storage.BlobTypeBlock
|
||||
@@ -526,12 +526,10 @@ func (self *SContainer) UploadStream(key string, reader io.Reader, contType stri
|
||||
}
|
||||
|
||||
func (self *SContainer) SignUrl(method string, key string, expire time.Duration) (string, error) {
|
||||
storageaccount := self.storageaccount
|
||||
client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env)
|
||||
blobService, err := self.storageaccount.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "NewBasicClientOnSovereignCloud")
|
||||
return "", errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
blobService := client.GetBlobService()
|
||||
containerRef := blobService.GetContainerReference(self.Name)
|
||||
sas := storage.ContainerSASOptions{}
|
||||
sas.Start = time.Now()
|
||||
@@ -557,12 +555,10 @@ func (self *SContainer) SignUrl(method string, key string, expire time.Duration)
|
||||
}
|
||||
|
||||
func (self *SContainer) UploadFile(filePath string) (string, error) {
|
||||
storageaccount := self.storageaccount
|
||||
client, err := storage.NewBasicClientOnSovereignCloud(storageaccount.Name, storageaccount.accountKey, storageaccount.region.client.env)
|
||||
blobService, err := self.storageaccount.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
blobService := client.GetBlobService()
|
||||
containerRef := blobService.GetContainerReference(self.Name)
|
||||
|
||||
err = ensureVHDSanity(filePath)
|
||||
@@ -595,7 +591,7 @@ func (self *SContainer) UploadFile(filePath string) (string, error) {
|
||||
VhdStream: diskStream,
|
||||
UploadableRanges: uploadableRanges,
|
||||
AlreadyProcessedBytes: common.TotalRangeLength(rangesToSkip),
|
||||
BlobServiceClient: blobService,
|
||||
BlobServiceClient: *blobService,
|
||||
ContainerName: self.Name,
|
||||
BlobName: blobName,
|
||||
Parallelism: 3,
|
||||
@@ -609,6 +605,48 @@ func (self *SContainer) UploadFile(filePath string) (string, error) {
|
||||
return blobRef.GetURL(), nil
|
||||
}
|
||||
|
||||
func (self *SContainer) getAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLPrivate
|
||||
containerRef, err := self.getContainerRef()
|
||||
if err != nil {
|
||||
log.Errorf("getContainerRef fail %s", err)
|
||||
return acl
|
||||
}
|
||||
output, err := containerRef.GetPermissions(nil)
|
||||
if err != nil {
|
||||
log.Errorf("containerRef.GetPermissions fail %s", err)
|
||||
return acl
|
||||
}
|
||||
switch output.AccessType {
|
||||
case storage.ContainerAccessTypePrivate:
|
||||
acl = cloudprovider.ACLPrivate
|
||||
case storage.ContainerAccessTypeContainer:
|
||||
acl = cloudprovider.ACLPublicRead
|
||||
}
|
||||
return acl
|
||||
}
|
||||
|
||||
func (self *SContainer) setAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
perm := storage.ContainerPermissions{}
|
||||
switch aclStr {
|
||||
case cloudprovider.ACLPublicRead:
|
||||
perm.AccessType = storage.ContainerAccessTypeContainer
|
||||
case cloudprovider.ACLPrivate:
|
||||
perm.AccessType = storage.ContainerAccessTypePrivate
|
||||
default:
|
||||
return errors.Error("unsupported ACL:" + string(aclStr))
|
||||
}
|
||||
containerRef, err := self.getContainerRef()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getContainerRef")
|
||||
}
|
||||
err = containerRef.SetPermissions(perm, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetPermissions")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SStorageAccount) UploadFile(containerName string, filePath string) (string, error) {
|
||||
container, err := self.getOrCreateContainer(containerName, true)
|
||||
if err != nil {
|
||||
@@ -679,8 +717,39 @@ func (b *SStorageAccount) GetStorageClass() string {
|
||||
return b.Sku.Tier
|
||||
}
|
||||
|
||||
func (b *SStorageAccount) GetAcl() string {
|
||||
return ""
|
||||
// get the common ACL of all containers
|
||||
func (b *SStorageAccount) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLPrivate
|
||||
containers, err := b.GetContainers()
|
||||
if err != nil {
|
||||
log.Errorf("GetContainers error %s", err)
|
||||
return acl
|
||||
}
|
||||
for i := range containers {
|
||||
aclC := containers[i].getAcl()
|
||||
if i == 0 {
|
||||
if aclC != acl {
|
||||
acl = aclC
|
||||
}
|
||||
} else if aclC != acl {
|
||||
acl = cloudprovider.ACLPrivate
|
||||
}
|
||||
}
|
||||
return acl
|
||||
}
|
||||
|
||||
func (b *SStorageAccount) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
containers, err := b.GetContainers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetContainers")
|
||||
}
|
||||
for i := range containers {
|
||||
err = containers[i].setAcl(aclStr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "containers.setAcl")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDesc(prefix, name string) string {
|
||||
@@ -729,6 +798,11 @@ func (b *SStorageAccount) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
return primary
|
||||
}
|
||||
|
||||
func (b *SStorageAccount) GetStats() cloudprovider.SBucketStats {
|
||||
stats, _ := cloudprovider.GetIBucketStats(b)
|
||||
return stats
|
||||
}
|
||||
|
||||
func (b *SStorageAccount) GetIObjects(prefix string, isRecursive bool) ([]cloudprovider.ICloudObject, error) {
|
||||
return cloudprovider.GetIObjects(b, prefix, isRecursive)
|
||||
}
|
||||
@@ -869,11 +943,10 @@ func (b *SStorageAccount) DeleteObject(ctx context.Context, key string) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "splitKey")
|
||||
}
|
||||
client, err := storage.NewBasicClientOnSovereignCloud(b.Name, b.accountKey, b.region.client.env)
|
||||
blobService, err := b.getBlobServiceClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "storage.NewBasicClientOnSovereignCloud")
|
||||
return errors.Wrap(err, "getBlobServiceClient")
|
||||
}
|
||||
blobService := client.GetBlobService()
|
||||
containerRef := blobService.GetContainerReference(containerName)
|
||||
if len(blob) > 0 {
|
||||
// delete object
|
||||
|
||||
@@ -140,7 +140,7 @@ func (self *SStoragecache) checkStorageAccount() (*SStorageAccount, error) {
|
||||
} else {
|
||||
for i := 0; i < len(storageaccounts); i++ {
|
||||
if id, ok := storageaccounts[i].Tags["id"]; ok && id == self.region.Name {
|
||||
storageaccount = &storageaccounts[i]
|
||||
storageaccount = storageaccounts[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package multicloud
|
||||
|
||||
import "yunion.io/x/jsonutils"
|
||||
|
||||
type SBaseBucket struct{}
|
||||
|
||||
func (b *SBaseBucket) GetId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBaseBucket) GetName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBaseBucket) GetGlobalId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBaseBucket) GetStatus() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBaseBucket) Refresh() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBaseBucket) IsEmulated() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *SBaseBucket) GetMetadata() *jsonutils.JSONDict {
|
||||
return nil
|
||||
}
|
||||
@@ -141,6 +141,10 @@ func (cli *SESXiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
return []cloudprovider.SSubAccount{subAccount}, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) GetAccountId() string {
|
||||
return cli.account
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) GetVersion() string {
|
||||
return cli.client.ServiceContent.About.Version
|
||||
}
|
||||
|
||||
@@ -165,6 +165,10 @@ func (self *SESXiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error)
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SESXiProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SESXiProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return nil
|
||||
}
|
||||
@@ -184,3 +188,7 @@ func (self *SESXiProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, er
|
||||
func (self *SESXiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (self *SESXiProvider) GetStorageClasses(regionId string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -15,33 +15,28 @@
|
||||
package huawei
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/minio-go"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei/obs"
|
||||
)
|
||||
|
||||
type SBucket struct {
|
||||
objectstore.SBucket
|
||||
multicloud.SBaseBucket
|
||||
|
||||
region *SRegion
|
||||
|
||||
Name string
|
||||
Location string
|
||||
CreationDate time.Time
|
||||
|
||||
StorageClass string
|
||||
Acl string
|
||||
|
||||
Size int64
|
||||
ObjectNumber int
|
||||
}
|
||||
|
||||
func (b *SBucket) GetProjectId() string {
|
||||
@@ -69,11 +64,72 @@ func (b *SBucket) GetCreateAt() time.Time {
|
||||
}
|
||||
|
||||
func (b *SBucket) GetStorageClass() string {
|
||||
return b.StorageClass
|
||||
obscli, err := b.region.getOBSClient()
|
||||
if err != nil {
|
||||
log.Errorf("b.region.getOBSClient error %s", err)
|
||||
return ""
|
||||
}
|
||||
output, err := obscli.GetBucketStoragePolicy(b.Name)
|
||||
if err != nil {
|
||||
log.Errorf("obscli.GetBucketStoragePolicy error %s", err)
|
||||
}
|
||||
return output.StorageClass
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() string {
|
||||
return b.Acl
|
||||
func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType {
|
||||
switch {
|
||||
case len(acls) == 1:
|
||||
if acls[0].Grantee.URI == "" && acls[0].Permission == minio.PERMISSION_FULL_CONTROL {
|
||||
return cloudprovider.ACLPrivate
|
||||
}
|
||||
case len(acls) == 2:
|
||||
for _, g := range acls {
|
||||
if g.Grantee.URI == minio.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == minio.PERMISSION_READ {
|
||||
return cloudprovider.ACLAuthRead
|
||||
}
|
||||
if g.Grantee.URI == minio.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == minio.PERMISSION_READ {
|
||||
return cloudprovider.ACLPublicRead
|
||||
}
|
||||
}
|
||||
case len(acls) == 3:
|
||||
for _, g := range acls {
|
||||
if g.Grantee.URI == minio.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == minio.PERMISSION_WRITE {
|
||||
return cloudprovider.ACLPublicReadWrite
|
||||
}
|
||||
}
|
||||
}
|
||||
return cloudprovider.ACLUnknown
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLPrivate
|
||||
obscli, err := b.region.getOBSClient()
|
||||
if err != nil {
|
||||
log.Errorf("b.region.getOBSClient error %s", err)
|
||||
return acl
|
||||
}
|
||||
output, err := obscli.GetBucketAcl(b.Name)
|
||||
if err != nil {
|
||||
log.Errorf("obscli.GetBucketAcl error %s", err)
|
||||
return acl
|
||||
}
|
||||
acl = obsAcl2CannedAcl(output.Grants)
|
||||
return acl
|
||||
}
|
||||
|
||||
func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error {
|
||||
obscli, err := b.region.getOBSClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "b.region.getOBSClient")
|
||||
}
|
||||
input := &obs.SetBucketAclInput{}
|
||||
input.Bucket = b.Name
|
||||
input.ACL = obs.AclType(string(acl))
|
||||
_, err = obscli.SetBucketAcl(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "obscli.SetBucketAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
@@ -89,12 +145,25 @@ func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SBucket) GetSizeByte() int64 {
|
||||
return b.Size
|
||||
}
|
||||
|
||||
func (b *SBucket) GetObjectNumber() int {
|
||||
return b.ObjectNumber
|
||||
func (b *SBucket) GetStats() cloudprovider.SBucketStats {
|
||||
stats := cloudprovider.SBucketStats{}
|
||||
obscli, err := b.region.getOBSClient()
|
||||
if err != nil {
|
||||
log.Errorf("b.region.getOBSClient error %s", err)
|
||||
stats.SizeBytes = -1
|
||||
stats.ObjectCount = -1
|
||||
return stats
|
||||
}
|
||||
output, err := obscli.GetBucketStorageInfo(b.Name)
|
||||
if err != nil {
|
||||
log.Errorf("obscli.GetBucketStorageInfo error %s", err)
|
||||
stats.SizeBytes = -1
|
||||
stats.ObjectCount = -1
|
||||
return stats
|
||||
}
|
||||
stats.SizeBytes = output.Size
|
||||
stats.ObjectCount = output.ObjectNumber
|
||||
return stats
|
||||
}
|
||||
|
||||
func (b *SBucket) GetIObjects(prefix string, isRecursive bool) ([]cloudprovider.ICloudObject, error) {
|
||||
|
||||
@@ -18,11 +18,15 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei/client"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/credentials"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei/obs"
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -52,7 +56,12 @@ type SHuaweiClient struct {
|
||||
accessUrl string // 服务区域 ChinaCloud | InternationalCloud
|
||||
accessKey string
|
||||
secret string
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
ownerId string
|
||||
ownerName string
|
||||
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
}
|
||||
|
||||
// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。
|
||||
@@ -78,11 +87,18 @@ func NewHuaweiClient(providerId, providerName, accessurl, accessKey, secret, pro
|
||||
func (self *SHuaweiClient) init() error {
|
||||
err := self.fetchRegions()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "fetchRegions")
|
||||
}
|
||||
err = self.initSigner()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "initSigner")
|
||||
}
|
||||
err = self.fetchBuckets()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetchOwner")
|
||||
}
|
||||
if self.debug {
|
||||
log.Debugf("OwnerId: %s OwnerName: %s", self.ownerId, self.ownerName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -134,6 +150,58 @@ func (self *SHuaweiClient) fetchRegions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) invalidateIBuckets() {
|
||||
self.iBuckets = nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if self.iBuckets == nil {
|
||||
err := self.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
return self.iBuckets, nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) fetchBuckets() error {
|
||||
if len(self.iregions) == 0 {
|
||||
return errors.Error("no region???")
|
||||
}
|
||||
region := self.iregions[0].(*SRegion)
|
||||
obscli, err := region.getOBSClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getOBSClient")
|
||||
}
|
||||
input := &obs.ListBucketsInput{QueryLocation: true}
|
||||
output, err := obscli.ListBuckets(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "obscli.ListBuckets")
|
||||
}
|
||||
self.ownerId = output.Owner.ID
|
||||
self.ownerName = output.Owner.DisplayName
|
||||
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range output.Buckets {
|
||||
bInfo := output.Buckets[i]
|
||||
region, err := self.getIRegionByRegionId(bInfo.Location)
|
||||
if err != nil {
|
||||
log.Errorf("fail to find region %s", bInfo.Location)
|
||||
continue
|
||||
}
|
||||
b := SBucket{
|
||||
region: region.(*SRegion),
|
||||
|
||||
Name: bInfo.Name,
|
||||
Location: bInfo.Location,
|
||||
CreationDate: bInfo.CreationDate,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
}
|
||||
self.iBuckets = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string {
|
||||
if len(self.projectId) > 0 {
|
||||
return self.iregions[0].GetGlobalId()
|
||||
@@ -188,10 +256,23 @@ func (self *SHuaweiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error)
|
||||
return subAccounts, nil
|
||||
}
|
||||
|
||||
func (client *SHuaweiClient) GetAccountId() string {
|
||||
return client.ownerId
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.iregions
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetId() == id {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SHuaweiClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetGlobalId() == id {
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
|
||||
package huawei
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/huawei/obs"
|
||||
)
|
||||
|
||||
type SObject struct {
|
||||
bucket *SBucket
|
||||
@@ -25,3 +31,34 @@ type SObject struct {
|
||||
func (o *SObject) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return o.bucket
|
||||
}
|
||||
|
||||
func (o *SObject) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLDefault
|
||||
obscli, err := o.bucket.region.getOBSClient()
|
||||
if err != nil {
|
||||
log.Errorf("o.bucket.region.GetOssClient error %s", err)
|
||||
return acl
|
||||
}
|
||||
input := &obs.GetObjectAclInput{}
|
||||
input.Bucket = o.bucket.Name
|
||||
input.Key = o.Key
|
||||
output, err := obscli.GetObjectAcl(input)
|
||||
acl = obsAcl2CannedAcl(output.Grants)
|
||||
return acl
|
||||
}
|
||||
|
||||
func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
obscli, err := o.bucket.region.getOBSClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "o.bucket.region.getOBSClient")
|
||||
}
|
||||
input := &obs.SetObjectAclInput{}
|
||||
input.Bucket = o.bucket.Name
|
||||
input.Key = o.Key
|
||||
input.ACL = obs.AclType(string(aclStr))
|
||||
_, err = obscli.SetObjectAcl(input)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "obscli.SetObjectAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (obsClient ObsClient) Close() {
|
||||
|
||||
func (obsClient ObsClient) ListBuckets(input *ListBucketsInput) (output *ListBucketsOutput, err error) {
|
||||
if input == nil {
|
||||
input = &ListBucketsInput{}
|
||||
input = &ListBucketsInput{QueryLocation: true}
|
||||
}
|
||||
output = &ListBucketsOutput{}
|
||||
err = obsClient.doActionWithoutBucket("ListBuckets", HTTP_GET, input, output)
|
||||
|
||||
@@ -156,6 +156,10 @@ func (self *SHuaweiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SHuaweiProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SHuaweiProvider) GetCloudRegionExternalIdPrefix() string {
|
||||
return self.client.GetCloudRegionExternalIdPrefix()
|
||||
}
|
||||
@@ -163,3 +167,9 @@ func (self *SHuaweiProvider) GetCloudRegionExternalIdPrefix() string {
|
||||
func (self *SHuaweiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SHuaweiProvider) GetStorageClasses(regionId string) []string {
|
||||
return []string{
|
||||
"STANDARD", "WARM", "COLD",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ func (self *SRegion) getECSClient() (*client.Client, error) {
|
||||
|
||||
regionId := strings.Split(project.Name, "_")[0]
|
||||
if regionId != self.ID {
|
||||
log.Debugf("project %s not in region %s", self.client.projectId, self.ID)
|
||||
return nil, nil
|
||||
// log.Debugf("project %s not in region %s", self.client.projectId, self.ID)
|
||||
return nil, errors.Error("region and project mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,26 +909,15 @@ func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAcces
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
obsClient, err := region.getOBSClient()
|
||||
iBuckets, err := region.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.getOBSClient")
|
||||
return nil, errors.Wrap(err, "getIBuckets")
|
||||
}
|
||||
input := &obs.ListBucketsInput{}
|
||||
input.QueryLocation = true
|
||||
output, err := obsClient.ListBuckets(input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ListBuckets")
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, len(output.Buckets))
|
||||
for i, bInfo := range output.Buckets {
|
||||
b := SBucket{
|
||||
region: region,
|
||||
|
||||
Name: bInfo.Name,
|
||||
Location: bInfo.Location,
|
||||
CreationDate: bInfo.CreationDate,
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range iBuckets {
|
||||
if iBuckets[i].GetLocation() == region.GetId() {
|
||||
ret = append(ret, iBuckets[i])
|
||||
}
|
||||
ret[i] = &b
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -974,6 +963,7 @@ func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "obsClient.CreateBucket")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -989,6 +979,7 @@ func (region *SRegion) DeleteIBucket(name string) error {
|
||||
}
|
||||
return errors.Wrap(err, "DeleteBucket")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1005,22 +996,11 @@ func (region *SRegion) IBucketExist(name string) (bool, error) {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
||||
obsClient, err := region.getOBSClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.getOBSClient")
|
||||
}
|
||||
info, err := obsClient.GetBucketStorageInfo(name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "obsClient.GetBucketStorageInfo")
|
||||
}
|
||||
b := SBucket{
|
||||
region: region,
|
||||
return cloudprovider.GetIBucketById(region, name)
|
||||
}
|
||||
|
||||
Name: name,
|
||||
Size: info.Size,
|
||||
ObjectNumber: info.ObjectNumber,
|
||||
}
|
||||
return &b, nil
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return region.GetIBucketById(name)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) {
|
||||
|
||||
@@ -40,4 +40,8 @@ func (cli *SNoObjectStorageRegion) GetIBucketById(name string) (cloudprovider.IC
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
func (cli *SNoObjectStorageRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return nil, cloudprovider.ErrNotSupported
|
||||
}
|
||||
|
||||
////////////////// END S3 fake API //////////
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
"github.com/minio/minio-go"
|
||||
"yunion.io/x/minio-go"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
@@ -72,8 +72,13 @@ func (bucket *SBucket) GetName() string {
|
||||
return bucket.Name
|
||||
}
|
||||
|
||||
func (bucket *SBucket) GetAcl() string {
|
||||
return bucket.Acl
|
||||
func (bucket *SBucket) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl, _ := bucket.client.GetIBucketAcl(bucket.Name)
|
||||
return acl
|
||||
}
|
||||
|
||||
func (bucket *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
return bucket.client.SetIBucketAcl(bucket.Name, aclStr)
|
||||
}
|
||||
|
||||
func (bucket *SBucket) GetLocation() string {
|
||||
@@ -92,6 +97,11 @@ func (bucket *SBucket) GetStorageClass() string {
|
||||
return bucket.StorageClass
|
||||
}
|
||||
|
||||
func (bucket *SBucket) GetStats() cloudprovider.SBucketStats {
|
||||
stats, _ := cloudprovider.GetIBucketStats(bucket)
|
||||
return stats
|
||||
}
|
||||
|
||||
func (bucket *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
return []cloudprovider.SBucketAccessUrl{
|
||||
{
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package objectstore
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
@@ -27,3 +29,20 @@ type SObject struct {
|
||||
func (o *SObject) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return o.bucket
|
||||
}
|
||||
|
||||
func (o *SObject) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl, err := o.bucket.client.GetObjectAcl(o.bucket.Name, o.Key)
|
||||
if err != nil {
|
||||
log.Errorf("o.bucket.client.GetObjectAcl error %s", err)
|
||||
return acl
|
||||
}
|
||||
return acl
|
||||
}
|
||||
|
||||
func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
err := o.bucket.client.SetObjectAcl(o.bucket.Name, o.Key, aclStr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "o.bucket.client.SetObjectAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/minio-go"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
|
||||
@@ -43,6 +43,11 @@ type SObjectStoreClient struct {
|
||||
accessKey string
|
||||
secret string
|
||||
|
||||
ownerId string
|
||||
ownerName string
|
||||
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
|
||||
client *minio.Client
|
||||
|
||||
Debug bool
|
||||
@@ -65,7 +70,7 @@ func NewObjectStoreClient(providerId string, providerName string, endpoint strin
|
||||
if parts.Scheme == "https" {
|
||||
useSsl = true
|
||||
}
|
||||
cli, err := minio.New(parts.Host, accessKey, secret, useSsl)
|
||||
cli, err := minio.New(parts.Host, accessKey, secret, useSsl, client.Debug)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "minio.New")
|
||||
}
|
||||
@@ -75,6 +80,13 @@ func NewObjectStoreClient(providerId string, providerName string, endpoint strin
|
||||
|
||||
client.client = cli
|
||||
|
||||
err = client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
|
||||
log.Debugf("clientID: %s Name: %s", client.ownerId, client.ownerName)
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
@@ -87,6 +99,10 @@ func (cli *SObjectStoreClient) GetSubAccounts() ([]cloudprovider.SSubAccount, er
|
||||
return []cloudprovider.SSubAccount{subAccount}, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetAccountId() string {
|
||||
return cli.ownerId
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIRegion() cloudprovider.ICloudRegion {
|
||||
return cli.GetVirtualObject().(cloudprovider.ICloudRegion)
|
||||
}
|
||||
@@ -261,20 +277,41 @@ func (cli *SObjectStoreClient) CreateISku(sku *cloudprovider.SServerSku) (cloudp
|
||||
////////////////////////////////// S3 API ///////////////////////////////////
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
buckets, err := cli.client.ListBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "client.ListBuckets")
|
||||
return cli.getIBuckets()
|
||||
}
|
||||
|
||||
func (self *SObjectStoreClient) invalidateIBuckets() {
|
||||
self.iBuckets = nil
|
||||
}
|
||||
|
||||
func (self *SObjectStoreClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if self.iBuckets == nil {
|
||||
err := self.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, len(buckets))
|
||||
return self.iBuckets, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) fetchBuckets() error {
|
||||
result, err := cli.client.ListBuckets()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "client.ListBuckets")
|
||||
}
|
||||
cli.ownerId = result.Owner.ID
|
||||
cli.ownerName = result.Owner.DisplayName
|
||||
buckets := result.Buckets.Bucket
|
||||
cli.iBuckets = make([]cloudprovider.ICloudBucket, len(buckets))
|
||||
for i := range buckets {
|
||||
b := SBucket{
|
||||
client: cli,
|
||||
Name: buckets[i].Name,
|
||||
CreatedAt: buckets[i].CreationDate,
|
||||
}
|
||||
ret[i] = &b
|
||||
cli.iBuckets[i] = &b
|
||||
}
|
||||
return ret, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) CreateIBucket(name string, storageClass string, acl string) error {
|
||||
@@ -282,6 +319,7 @@ func (cli *SObjectStoreClient) CreateIBucket(name string, storageClass string, a
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "MakeBucket")
|
||||
}
|
||||
cli.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -303,6 +341,111 @@ func (cli *SObjectStoreClient) DeleteIBucket(name string) error {
|
||||
}
|
||||
return errors.Wrap(err, "RemoveBucket")
|
||||
}
|
||||
cli.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketLocation(name string) (string, error) {
|
||||
info, err := cli.client.GetBucketLocation(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketLocation")
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketWebsite(name string) (string, error) {
|
||||
info, err := cli.client.GetBucketWebsite(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketWebsite")
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketReferer(name string) (string, error) {
|
||||
info, err := cli.client.GetBucketReferer(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketReferer")
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketCors(name string) (string, error) {
|
||||
info, err := cli.client.GetBucketCors(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketCors")
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketLogging(name string) (*minio.BucketLoggingStatus, error) {
|
||||
info, err := cli.client.GetBucketLogging(name)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetBucketLogging")
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) SetIBucketLogging(name string, target string, targetPrefix string, email string) error {
|
||||
conf := minio.BucketLoggingStatus{}
|
||||
if len(target) > 0 {
|
||||
conf.LoggingEnabled.TargetBucket = target
|
||||
conf.LoggingEnabled.TargetPrefix = targetPrefix
|
||||
conf.LoggingEnabled.TargetGrants.Grant = []minio.Grant{
|
||||
{
|
||||
Grantee: minio.Grantee{
|
||||
Type: minio.GRANTEE_TYPE_EMAIL,
|
||||
EmailAddress: email,
|
||||
},
|
||||
Permission: minio.PERMISSION_FULL_CONTROL,
|
||||
},
|
||||
}
|
||||
}
|
||||
err := cli.client.SetBucketLogging(name, conf)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetBucketLogging")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketInfo(name string) (string, error) {
|
||||
info, err := cli.client.GetBucketInfo(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketInfo")
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketAcl(name string) (cloudprovider.TBucketACLType, error) {
|
||||
acl, err := cli.client.GetBucketAcl(name)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketAcl")
|
||||
}
|
||||
return cloudprovider.TBucketACLType(acl.GetCannedACL()), nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) SetIBucketAcl(name string, cannedAcl cloudprovider.TBucketACLType) error {
|
||||
acl := minio.CannedAcl(cli.ownerId, cli.ownerName, string(cannedAcl))
|
||||
err := cli.client.SetBucketAcl(name, acl)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetBucketAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetObjectAcl(bucket, key string) (cloudprovider.TBucketACLType, error) {
|
||||
acl, err := cli.client.GetObjectACL(bucket, key)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "GetBucketAcl")
|
||||
}
|
||||
return cloudprovider.TBucketACLType(acl.GetCannedACL()), nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) SetObjectAcl(bucket, key string, cannedAcl cloudprovider.TBucketACLType) error {
|
||||
acl := minio.CannedAcl(cli.ownerId, cli.ownerName, string(cannedAcl))
|
||||
err := cli.client.SetObjectAcl(bucket, key, acl)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetObjectAcl")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -331,13 +474,20 @@ func (cli *SObjectStoreClient) GetIBucketLiftcycle(name string) (string, error)
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) IBucketExist(name string) (bool, error) {
|
||||
exist, err := cli.client.BucketExists(name)
|
||||
exist, header, err := cli.client.BucketExists(name)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "BucketExists")
|
||||
}
|
||||
if header != nil {
|
||||
log.Debugf("header: %s", jsonutils.Marshal(header))
|
||||
}
|
||||
return exist, nil
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return cloudprovider.GetIBucketById(cli, name)
|
||||
}
|
||||
|
||||
func (cli *SObjectStoreClient) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return cli.GetIBucketById(name)
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ func (self *SObjectStoreProviderFactory) GetName() string {
|
||||
return api.CLOUD_PROVIDER_GENERICS3
|
||||
}
|
||||
|
||||
func (factory *SObjectStoreProviderFactory) IsSupportObjectStorage() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (self *SObjectStoreProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) error {
|
||||
accessKeyID, _ := data.GetString("access_key_id")
|
||||
if len(accessKeyID) == 0 {
|
||||
@@ -134,3 +138,11 @@ func (self *SObjectStoreProvider) GetVersion() string {
|
||||
func (self *SObjectStoreProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SObjectStoreProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SObjectStoreProvider) GetStorageClasses(regionId string) []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,28 @@ func S3Shell() {
|
||||
})
|
||||
|
||||
type BucketCreateOptions struct {
|
||||
NAME string `help:"name of bucket to create"`
|
||||
NAME string `help:"name of bucket to create"`
|
||||
Acl string `help:"ACL string" choices:"private|public-read|public-read-write"`
|
||||
StorageClass string `help:"StorageClass" choices:"STANDARD|IA|ARCHIVE"`
|
||||
}
|
||||
shellutils.R(&BucketCreateOptions{}, "bucket-create", "Create bucket", func(cli cloudprovider.ICloudRegion, args *BucketCreateOptions) error {
|
||||
err := cli.CreateIBucket(args.NAME, "", "")
|
||||
err := cli.CreateIBucket(args.NAME, args.StorageClass, args.Acl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketAclOptions struct {
|
||||
BUCKET string `help:"name of bucket"`
|
||||
ACL string `help:"ACL string" choices:"private|public-read|public-read-write"`
|
||||
}
|
||||
shellutils.R(&BucketAclOptions{}, "bucket-set-acl", "Create bucket", func(cli cloudprovider.ICloudRegion, args *BucketAclOptions) error {
|
||||
bucket, err := cli.GetIBucketById(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = bucket.SetAcl(cloudprovider.TBucketACLType(args.ACL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -201,4 +219,49 @@ func S3Shell() {
|
||||
fmt.Println(urlStr)
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketAclOption struct {
|
||||
BUCKET string `help:"name of bucket to put object"`
|
||||
KEY string `help:"key of object"`
|
||||
}
|
||||
shellutils.R(&BucketAclOption{}, "object-acl", "Get object acl", func(cli cloudprovider.ICloudRegion, args *BucketAclOption) error {
|
||||
bucket, err := cli.GetIBucketById(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objects, err := bucket.GetIObjects(args.KEY, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(objects) == 0 {
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
fmt.Println(objects[0].GetAcl())
|
||||
return nil
|
||||
})
|
||||
|
||||
type BucketSetAclOption struct {
|
||||
BUCKET string `help:"name of bucket to put object"`
|
||||
KEY string `help:"key of object"`
|
||||
ACL string `help:"Target acl" choices:"default|private|public-read|public-read-write"`
|
||||
}
|
||||
shellutils.R(&BucketSetAclOption{}, "object-set-acl", "Get object acl", func(cli cloudprovider.ICloudRegion, args *BucketSetAclOption) error {
|
||||
bucket, err := cli.GetIBucketById(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objects, err := bucket.GetIObjects(args.KEY, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(objects) == 0 {
|
||||
return cloudprovider.ErrNotFound
|
||||
}
|
||||
err = objects[0].SetAcl(cloudprovider.TBucketACLType(args.ACL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Success!")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
"yunion.io/x/onecloud/pkg/util/shellutils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
type MinioBucketOption struct {
|
||||
BUCKET string `help:"name of bucket"`
|
||||
}
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-head", "HEAD bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
cli.IBucketExist(args.BUCKET)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-acl", "Get ACL of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
acl, err := cli.GetIBucketAcl(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("ACL:", acl)
|
||||
return nil
|
||||
})
|
||||
|
||||
type MinioBucketCannedAclConfigOption struct {
|
||||
BUCKET string `help:"name of bucket"`
|
||||
ACL string `help:"canned ACL" choices:"private|public-read|public-read-write|auth-read"`
|
||||
}
|
||||
shellutils.R(&MinioBucketCannedAclConfigOption{}, "bucket-canned-acl-config", "Set canned ACL of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketCannedAclConfigOption) error {
|
||||
err := cli.SetIBucketAcl(args.BUCKET, cloudprovider.TBucketACLType(args.ACL))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-policy", "Get Policy of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
policy, err := cli.GetIBucketPolicy(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Policy:", policy)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-lifecycle", "Get lifecycle of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
lifecycle, err := cli.GetIBucketLiftcycle(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Lifecycle:", lifecycle)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-info", "Get info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
info, err := cli.GetIBucketInfo(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Info:", info)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-location", "Get location of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
info, err := cli.GetIBucketLocation(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Info:", info)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-website", "Get website info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
info, err := cli.GetIBucketWebsite(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Info:", info)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-logging", "Get logging configuration of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
info, err := cli.GetIBucketLogging(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Logging:", info)
|
||||
return nil
|
||||
})
|
||||
|
||||
type MinioSetLoggingOption struct {
|
||||
BUCKET string `help:"id or name of bucket"`
|
||||
Target string `help:"target bucket"`
|
||||
Prefix string `help:"target prefix"`
|
||||
Email string `help:"email"`
|
||||
}
|
||||
shellutils.R(&MinioSetLoggingOption{}, "bucket-logging-config", "Set logging configuration of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioSetLoggingOption) error {
|
||||
err := cli.SetIBucketLogging(args.BUCKET, args.Target, args.Prefix, args.Email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-referer", "Get info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
info, err := cli.GetIBucketReferer(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Info:", info)
|
||||
return nil
|
||||
})
|
||||
|
||||
shellutils.R(&MinioBucketOption{}, "bucket-cors", "Get info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error {
|
||||
info, err := cli.GetIBucketCors(args.BUCKET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Info:", info)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -170,6 +170,10 @@ func (self *SOpenStackProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, e
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SOpenStackProvider) GetAccountId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SOpenStackProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -189,3 +193,7 @@ func (self *SOpenStackProvider) GetCloudRegionExternalIdPrefix() string {
|
||||
func (self *SOpenStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SOpenStackProvider) GetStorageClasses(regionId string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -506,3 +506,7 @@ func (region *SRegion) IBucketExist(name string) (bool, error) {
|
||||
func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -20,25 +20,26 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
|
||||
"github.com/tencentyun/cos-go-sdk-v5"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/minio-go"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
)
|
||||
|
||||
type SBucket struct {
|
||||
objectstore.SBucket
|
||||
multicloud.SBaseBucket
|
||||
|
||||
region *SRegion
|
||||
|
||||
Name string
|
||||
FullName string
|
||||
Location string
|
||||
CreateDate time.Time
|
||||
Acl string
|
||||
}
|
||||
|
||||
func (b *SBucket) GetProjectId() string {
|
||||
@@ -69,8 +70,64 @@ func (b *SBucket) GetStorageClass() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() string {
|
||||
return b.Acl
|
||||
const (
|
||||
ACL_GROUP_URI_ALL_USERS = "http://cam.qcloud.com/groups/global/AllUsers"
|
||||
ACL_GROUP_URI_AUTH_USERS = "http://cam.qcloud.com/groups/global/AuthenticatedUsers"
|
||||
)
|
||||
|
||||
func cosAcl2CannedAcl(acls []cos.ACLGrant) cloudprovider.TBucketACLType {
|
||||
switch {
|
||||
case len(acls) == 1:
|
||||
if acls[0].Grantee.URI == "" && acls[0].Permission == minio.PERMISSION_FULL_CONTROL {
|
||||
return cloudprovider.ACLPrivate
|
||||
}
|
||||
case len(acls) == 2:
|
||||
for _, g := range acls {
|
||||
if g.Grantee.URI == ACL_GROUP_URI_AUTH_USERS && g.Permission == minio.PERMISSION_READ {
|
||||
return cloudprovider.ACLAuthRead
|
||||
}
|
||||
if g.Grantee.URI == ACL_GROUP_URI_ALL_USERS && g.Permission == minio.PERMISSION_READ {
|
||||
return cloudprovider.ACLPublicRead
|
||||
}
|
||||
}
|
||||
case len(acls) == 3:
|
||||
for _, g := range acls {
|
||||
if g.Grantee.URI == ACL_GROUP_URI_ALL_USERS && g.Permission == minio.PERMISSION_WRITE {
|
||||
return cloudprovider.ACLPublicReadWrite
|
||||
}
|
||||
}
|
||||
}
|
||||
return cloudprovider.ACLUnknown
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLPrivate
|
||||
coscli, err := b.region.GetCosClient(b)
|
||||
if err != nil {
|
||||
log.Errorf("GetCosClient fail %s", err)
|
||||
return acl
|
||||
}
|
||||
result, _, err := coscli.Bucket.GetACL(context.Background())
|
||||
if err != nil {
|
||||
log.Errorf("coscli.Bucket.GetACL fail %s", err)
|
||||
return acl
|
||||
}
|
||||
return cosAcl2CannedAcl(result.AccessControlList)
|
||||
}
|
||||
|
||||
func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
coscli, err := b.region.GetCosClient(b)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "b.region.GetCosClient")
|
||||
}
|
||||
opts := &cos.BucketPutACLOptions{}
|
||||
opts.Header = &cos.ACLHeaderOptions{}
|
||||
opts.Header.XCosACL = string(aclStr)
|
||||
_, err = coscli.Bucket.PutACL(context.Background(), opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "PutACL")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *SBucket) getBucketUrl() string {
|
||||
@@ -90,6 +147,11 @@ func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SBucket) GetStats() cloudprovider.SBucketStats {
|
||||
stats, _ := cloudprovider.GetIBucketStats(b)
|
||||
return stats
|
||||
}
|
||||
|
||||
func (b *SBucket) GetIObjects(prefix string, isRecursive bool) ([]cloudprovider.ICloudObject, error) {
|
||||
return cloudprovider.GetIObjects(b, prefix, isRecursive)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,14 @@
|
||||
|
||||
package qcloud
|
||||
|
||||
import "yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"context"
|
||||
"github.com/tencentyun/cos-go-sdk-v5"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
type SObject struct {
|
||||
bucket *SBucket
|
||||
@@ -25,3 +32,32 @@ type SObject struct {
|
||||
func (o *SObject) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return o.bucket
|
||||
}
|
||||
|
||||
func (o *SObject) GetAcl() cloudprovider.TBucketACLType {
|
||||
acl := cloudprovider.ACLDefault
|
||||
coscli, err := o.bucket.region.GetCosClient(o.bucket)
|
||||
if err != nil {
|
||||
log.Errorf("o.bucket.region.GetOssClient error %s", err)
|
||||
return acl
|
||||
}
|
||||
result, _, err := coscli.Object.GetACL(context.Background(), o.Key)
|
||||
if err != nil {
|
||||
log.Errorf("coscli.Object.GetACL error %s", err)
|
||||
return acl
|
||||
}
|
||||
return cosAcl2CannedAcl(result.AccessControlList)
|
||||
}
|
||||
|
||||
func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
coscli, err := o.bucket.region.GetCosClient(o.bucket)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "o.bucket.region.GetCosClient")
|
||||
}
|
||||
opts := &cos.ObjectPutACLOptions{}
|
||||
opts.Header.XCosACL = string(aclStr)
|
||||
_, err = coscli.Object.PutACL(context.Background(), o.Key, opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "coscli.Object.PutACL")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -147,6 +147,10 @@ func (self *SQcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SQcloudProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SQcloudProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -170,3 +174,9 @@ func (self *SQcloudProvider) GetBalance() (float64, string, error) {
|
||||
func (self *SQcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SQcloudProvider) GetStorageClasses(regionId string) []string {
|
||||
return []string{
|
||||
"STANDARD", "STANDARD_IA", "ARCHIVE",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
package qcloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -24,12 +27,16 @@ import (
|
||||
sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
"github.com/tencentyun/cos-go-sdk-v5"
|
||||
"github.com/tencentyun/cos-go-sdk-v5/debug"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -49,7 +56,12 @@ type SQcloudClient struct {
|
||||
AppID string
|
||||
SecretID string
|
||||
SecretKey string
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
ownerId string
|
||||
ownerName string
|
||||
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
|
||||
Debug bool
|
||||
}
|
||||
@@ -65,7 +77,14 @@ func NewQcloudClient(providerId string, providerName string, secretID string, se
|
||||
}
|
||||
err := client.fetchRegions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "fetchRegions")
|
||||
}
|
||||
err = client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
if isDebug {
|
||||
log.Debugf("ownerID: %s ownerName: %s", client.ownerId, client.ownerName)
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
@@ -455,6 +474,84 @@ func (client *SQcloudClient) fetchRegions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) getCosClient(bucket *SBucket) (*cos.Client, error) {
|
||||
var baseUrl *cos.BaseURL
|
||||
if bucket != nil {
|
||||
u, _ := url.Parse(bucket.getBucketUrl())
|
||||
baseUrl = &cos.BaseURL{
|
||||
BucketURL: u,
|
||||
}
|
||||
}
|
||||
cosClient := cos.NewClient(
|
||||
baseUrl,
|
||||
&http.Client{
|
||||
Transport: &cos.AuthorizationTransport{
|
||||
SecretID: client.SecretID,
|
||||
SecretKey: client.SecretKey,
|
||||
Transport: &debug.DebugRequestTransport{
|
||||
RequestHeader: client.Debug,
|
||||
RequestBody: client.Debug,
|
||||
ResponseHeader: client.Debug,
|
||||
ResponseBody: client.Debug,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
return cosClient, nil
|
||||
}
|
||||
|
||||
func (self *SQcloudClient) invalidateIBuckets() {
|
||||
self.iBuckets = nil
|
||||
}
|
||||
|
||||
func (self *SQcloudClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if self.iBuckets == nil {
|
||||
err := self.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
return self.iBuckets, nil
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) fetchBuckets() error {
|
||||
coscli, err := client.getCosClient(nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "GetCosClient")
|
||||
}
|
||||
s, _, err := coscli.Service.Get(context.Background())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "coscli.Service.Get")
|
||||
}
|
||||
client.ownerId = s.Owner.ID
|
||||
client.ownerName = s.Owner.DisplayName
|
||||
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range s.Buckets {
|
||||
bInfo := s.Buckets[i]
|
||||
createAt, _ := timeutils.ParseTimeStr(bInfo.CreationDate)
|
||||
name := bInfo.Name
|
||||
// name = name[:len(name)-len(result.Owner.ID)-1]
|
||||
name = name[:strings.LastIndexByte(name, '-')]
|
||||
region, err := client.getIRegionByRegionId(bInfo.Region)
|
||||
if err != nil {
|
||||
log.Errorf("fail to find region %s", bInfo.Region)
|
||||
continue
|
||||
}
|
||||
b := SBucket{
|
||||
region: region.(*SRegion),
|
||||
|
||||
Name: name,
|
||||
FullName: bInfo.Name,
|
||||
Location: bInfo.Region,
|
||||
CreateDate: createAt,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
}
|
||||
client.iBuckets = ret
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
|
||||
err := client.fetchRegions()
|
||||
if err != nil {
|
||||
@@ -470,6 +567,10 @@ func (client *SQcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
return []cloudprovider.SSubAccount{subAccount}, nil
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) GetAccountId() string {
|
||||
return client.ownerName
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return client.iregions
|
||||
}
|
||||
@@ -481,6 +582,15 @@ func (client *SQcloudClient) getDefaultRegion() (cloudprovider.ICloudRegion, err
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(client.iregions); i++ {
|
||||
if client.iregions[i].GetId() == id {
|
||||
return client.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (client *SQcloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(client.iregions); i++ {
|
||||
if client.iregions[i].GetGlobalId() == id {
|
||||
|
||||
@@ -17,9 +17,6 @@ package qcloud
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tencentyun/cos-go-sdk-v5"
|
||||
@@ -27,10 +24,8 @@ import (
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/timeutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
"github.com/tencentyun/cos-go-sdk-v5/debug"
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
@@ -285,29 +280,7 @@ func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudpro
|
||||
}
|
||||
|
||||
func (self *SRegion) GetCosClient(bucket *SBucket) (*cos.Client, error) {
|
||||
var baseUrl *cos.BaseURL
|
||||
if bucket != nil {
|
||||
u, _ := url.Parse(bucket.getBucketUrl())
|
||||
baseUrl = &cos.BaseURL{
|
||||
BucketURL: u,
|
||||
}
|
||||
}
|
||||
cosClient := cos.NewClient(
|
||||
baseUrl,
|
||||
&http.Client{
|
||||
Transport: &cos.AuthorizationTransport{
|
||||
SecretID: self.client.SecretID,
|
||||
SecretKey: self.client.SecretKey,
|
||||
Transport: &debug.DebugRequestTransport{
|
||||
RequestHeader: self.client.Debug,
|
||||
RequestBody: self.client.Debug,
|
||||
ResponseHeader: self.client.Debug,
|
||||
ResponseBody: self.client.Debug,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
return cosClient, nil
|
||||
return self.client.getCosClient(bucket)
|
||||
}
|
||||
|
||||
func (self *SRegion) GetClient() *SQcloudClient {
|
||||
@@ -854,34 +827,16 @@ func (self *SRegion) getCosEndpoint() string {
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
coscli, err := region.GetCosClient(nil)
|
||||
iBuckets, err := region.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "GetCosClient")
|
||||
}
|
||||
s, _, err := coscli.Service.Get(context.Background())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "coscli.Service.Get")
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range s.Buckets {
|
||||
bInfo := s.Buckets[i]
|
||||
// ignore buckets not belong to this region
|
||||
if bInfo.Region != region.GetId() {
|
||||
for i := range iBuckets {
|
||||
if iBuckets[i].GetLocation() != region.GetId() {
|
||||
continue
|
||||
}
|
||||
createAt, _ := timeutils.ParseTimeStr(bInfo.CreationDate)
|
||||
name := bInfo.Name
|
||||
// name = name[:len(name)-len(result.Owner.ID)-1]
|
||||
name = name[:strings.LastIndexByte(name, '-')]
|
||||
b := SBucket{
|
||||
region: region,
|
||||
|
||||
Name: name,
|
||||
FullName: bInfo.Name,
|
||||
Location: bInfo.Region,
|
||||
CreateDate: createAt,
|
||||
}
|
||||
ret = append(ret, &b)
|
||||
ret = append(ret, iBuckets[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -910,6 +865,7 @@ func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "coscli.Bucket.Put")
|
||||
}
|
||||
region.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -960,3 +916,7 @@ func (region *SRegion) IBucketExist(name string) (bool, error) {
|
||||
func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return cloudprovider.GetIBucketById(region, name)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return region.GetIBucketById(name)
|
||||
}
|
||||
|
||||
@@ -146,6 +146,10 @@ func (self *SUcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetAccountId() string {
|
||||
return self.client.GetAccountId()
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -161,3 +165,9 @@ func (self *SUcloudProvider) GetBalance() (float64, string, error) {
|
||||
func (self *SUcloudProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) {
|
||||
return nil, cloudprovider.ErrNotImplemented
|
||||
}
|
||||
|
||||
func (self *SUcloudProvider) GetStorageClasses(regionId string) []string {
|
||||
return []string{
|
||||
"STANDARD", "IA", "ARCHIVE",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,7 +644,7 @@ func (self *SRegion) GetClient() *SUcloudClient {
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/ufile-api/describe_bucket
|
||||
func (region *SRegion) listBuckets(name string, offset int, limit int) ([]SBucket, error) {
|
||||
func (client *SUcloudClient) listBuckets(name string, offset int, limit int) ([]SBucket, error) {
|
||||
params := NewUcloudParams()
|
||||
if len(name) > 0 {
|
||||
params.Set("BucketName", name)
|
||||
@@ -654,36 +654,33 @@ func (region *SRegion) listBuckets(name string, offset int, limit int) ([]SBucke
|
||||
}
|
||||
buckets := make([]SBucket, 0)
|
||||
// request without RegionId
|
||||
err := region.client.DoAction("DescribeBucket", params, &buckets)
|
||||
err := client.DoAction("DescribeBucket", params, &buckets)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DoAction DescribeBucket")
|
||||
}
|
||||
return buckets, nil
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/ufile-api/update_bucket
|
||||
func (region *SRegion) updateBucket(name string, aclType string) error {
|
||||
params := NewUcloudParams()
|
||||
params.Set("BucketName", name)
|
||||
params.Set("ProjectId", region.client.projectId)
|
||||
params.Set("Type", aclType)
|
||||
return region.client.DoAction("UpdateBucket", params, nil)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
buckets := make([]SBucket, 0)
|
||||
offset := 0
|
||||
limit := 50
|
||||
for {
|
||||
parts, err := region.listBuckets("", offset, limit)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "region.listBuckets")
|
||||
}
|
||||
if len(parts) > 0 {
|
||||
buckets = append(buckets, parts...)
|
||||
}
|
||||
if len(parts) < limit {
|
||||
break
|
||||
} else {
|
||||
offset += limit
|
||||
}
|
||||
iBuckets, err := region.client.getIBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getIBuckets")
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, len(buckets))
|
||||
for i := range buckets {
|
||||
buckets[i].region = region
|
||||
buckets[i].projectId = region.client.projectId
|
||||
ret[i] = &buckets[i]
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range iBuckets {
|
||||
if iBuckets[i].GetLocation() != region.GetId() {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, iBuckets[i])
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -707,7 +704,7 @@ func (region *SRegion) DeleteIBucket(name string) error {
|
||||
}
|
||||
|
||||
func (region *SRegion) IBucketExist(name string) (bool, error) {
|
||||
parts, err := region.listBuckets(name, 0, 1)
|
||||
parts, err := region.client.listBuckets(name, 0, 1)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "region.listBuckets")
|
||||
}
|
||||
@@ -717,6 +714,10 @@ func (region *SRegion) IBucketExist(name string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return cloudprovider.GetIBucketById(region, name)
|
||||
func (region *SRegion) GetIBucketById(bucketId string) (cloudprovider.ICloudBucket, error) {
|
||||
return cloudprovider.GetIBucketById(region, bucketId)
|
||||
}
|
||||
|
||||
func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) {
|
||||
return region.GetIBucketByName(name)
|
||||
}
|
||||
|
||||
@@ -184,11 +184,12 @@ func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.To
|
||||
return "", errors.Wrap(err, "GetIBucketByName")
|
||||
}
|
||||
file := SFile{
|
||||
bucket: bucket.(*SBucket),
|
||||
File: reader,
|
||||
FileSize: size,
|
||||
bucket: bucket.(*SBucket),
|
||||
file: reader,
|
||||
|
||||
Size: size,
|
||||
FileName: image.ImageId,
|
||||
FileMD5: md5,
|
||||
Hash: md5,
|
||||
}
|
||||
|
||||
err = file.Upload()
|
||||
@@ -274,14 +275,24 @@ func (self *SRegion) CreateBucket(name, bucketType string) error {
|
||||
params := NewUcloudParams()
|
||||
params.Set("BucketName", name)
|
||||
params.Set("Type", bucketType)
|
||||
return self.DoAction("CreateBucket", params, nil)
|
||||
err := self.DoAction("CreateBucket", params, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/ufile-api/delete_bucket
|
||||
func (self *SRegion) DeleteBucket(name string) error {
|
||||
params := NewUcloudParams()
|
||||
params.Set("BucketName", name)
|
||||
return self.DoAction("DeleteBucket", params, nil)
|
||||
err := self.DoAction("DeleteBucket", params, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.client.invalidateIBuckets()
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://docs.ucloud.cn/api/ufile-api/put_file
|
||||
|
||||
@@ -19,6 +19,9 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
)
|
||||
@@ -59,7 +62,9 @@ type SUcloudClient struct {
|
||||
accessKeyId string
|
||||
accessKeySecret string
|
||||
projectId string
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
|
||||
iregions []cloudprovider.ICloudRegion
|
||||
iBuckets []cloudprovider.ICloudBucket
|
||||
|
||||
httpClient *http.Client
|
||||
Debug bool
|
||||
@@ -81,6 +86,11 @@ func NewUcloudClient(providerId string, providerName string, accessKey string, s
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
@@ -167,6 +177,54 @@ func (self *SUcloudClient) fetchRegions() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *SUcloudClient) invalidateIBuckets() {
|
||||
client.iBuckets = nil
|
||||
}
|
||||
|
||||
func (client *SUcloudClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) {
|
||||
if client.iBuckets == nil {
|
||||
err := client.fetchBuckets()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchBuckets")
|
||||
}
|
||||
}
|
||||
return client.iBuckets, nil
|
||||
}
|
||||
|
||||
func (client *SUcloudClient) fetchBuckets() error {
|
||||
buckets := make([]SBucket, 0)
|
||||
offset := 0
|
||||
limit := 50
|
||||
for {
|
||||
parts, err := client.listBuckets("", offset, limit)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "client.listBuckets")
|
||||
}
|
||||
if len(parts) > 0 {
|
||||
buckets = append(buckets, parts...)
|
||||
}
|
||||
if len(parts) < limit {
|
||||
break
|
||||
} else {
|
||||
offset += limit
|
||||
}
|
||||
}
|
||||
ret := make([]cloudprovider.ICloudBucket, 0)
|
||||
for i := range buckets {
|
||||
region, err := client.getIRegionByRegionId(buckets[i].Region)
|
||||
if err != nil {
|
||||
log.Errorf("fail to find iregion %s", buckets[i].Region)
|
||||
continue
|
||||
}
|
||||
buckets[i].region = region.(*SRegion)
|
||||
ret = append(ret, &buckets[i])
|
||||
}
|
||||
|
||||
client.iBuckets = ret
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetRegions() []SRegion {
|
||||
regions := make([]SRegion, len(self.iregions))
|
||||
for i := 0; i < len(regions); i += 1 {
|
||||
@@ -196,10 +254,38 @@ func (self *SUcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error)
|
||||
return subAccounts, nil
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetAccountId() string {
|
||||
return "" // no account ID found for ucloud
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.iregions
|
||||
}
|
||||
|
||||
func removeDigit(idstr string) string {
|
||||
for len(idstr) > 0 && idstr[len(idstr)-1] >= '0' && idstr[len(idstr)-1] <= '9' {
|
||||
idstr = idstr[:len(idstr)-1]
|
||||
}
|
||||
return idstr
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetId() == id {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
// retry
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
rid := removeDigit(self.iregions[i].GetId())
|
||||
rid2 := removeDigit(id)
|
||||
if rid == rid2 {
|
||||
return self.iregions[i], nil
|
||||
}
|
||||
}
|
||||
return nil, cloudprovider.ErrNotFound
|
||||
}
|
||||
|
||||
func (self *SUcloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
|
||||
for i := 0; i < len(self.iregions); i += 1 {
|
||||
if self.iregions[i].GetGlobalId() == id {
|
||||
|
||||
+159
-43
@@ -15,6 +15,7 @@
|
||||
package ucloud
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
@@ -25,21 +26,21 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/multicloud/objectstore"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"context"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/cloudprovider"
|
||||
"yunion.io/x/onecloud/pkg/multicloud"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
)
|
||||
|
||||
type SBucket struct {
|
||||
objectstore.SBucket
|
||||
multicloud.SBaseBucket
|
||||
|
||||
region *SRegion
|
||||
|
||||
projectId string
|
||||
// projectId string
|
||||
|
||||
Domain Domain `json:"Domain"`
|
||||
BucketID string `json:"BucketId"`
|
||||
@@ -64,18 +65,21 @@ type Domain struct {
|
||||
type SFile struct {
|
||||
bucket *SBucket
|
||||
|
||||
// BucketName string
|
||||
File io.Reader
|
||||
FileSize int64
|
||||
FileName string
|
||||
FileMD5 string
|
||||
BucketName string `json:"BucketName"`
|
||||
FileName string `json:"FileName"`
|
||||
Size int64 `json:"Size"`
|
||||
Hash string `json:"Hash"`
|
||||
MimeType string `json:"MimeType"`
|
||||
CreateTime int64 `json:"CreateTime"`
|
||||
ModifyTime int64 `json:"ModifyTime"`
|
||||
StorageClass string `json:"StorageClass"`
|
||||
|
||||
file io.Reader
|
||||
}
|
||||
|
||||
func (self *SFile) signHeader(httpMethod string) string {
|
||||
md5 := ""
|
||||
func (client *SUcloudClient) signHeader(httpMethod string, path string, md5 string) string {
|
||||
contentType := ""
|
||||
if httpMethod == http.MethodPut {
|
||||
md5 = self.FileMD5
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
|
||||
@@ -83,25 +87,24 @@ func (self *SFile) signHeader(httpMethod string) string {
|
||||
data += md5 + "\n"
|
||||
data += contentType + "\n"
|
||||
data += "\n"
|
||||
data += "/" + self.bucket.BucketName + "/" + self.FileName
|
||||
data += path
|
||||
|
||||
h := hmac.New(sha1.New, []byte(self.bucket.region.client.accessKeySecret))
|
||||
log.Debugf("sign %s", data)
|
||||
h := hmac.New(sha1.New, []byte(client.accessKeySecret))
|
||||
h.Write([]byte(data))
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func (self *SFile) signHeader(httpMethod string) string {
|
||||
return self.bucket.region.client.signHeader(httpMethod, "/"+self.bucket.BucketName+"/"+self.FileName, self.Hash)
|
||||
}
|
||||
|
||||
func (self *SFile) auth(httpMethod string) string {
|
||||
return "UCloud" + " " + self.bucket.region.client.accessKeyId + ":" + self.signHeader(httpMethod)
|
||||
}
|
||||
|
||||
func (self *SFile) GetHost() string {
|
||||
return self.bucket.Domain.Src[0]
|
||||
/*host, err := self.bucket.region.GetBucketDomain(self.BucketName)
|
||||
if err != nil {
|
||||
log.Errorf("SFile GetHost %s", err)
|
||||
return ""
|
||||
}
|
||||
return host*/
|
||||
}
|
||||
|
||||
func (self *SFile) GetUrl() string {
|
||||
@@ -127,38 +130,117 @@ func (self *SFile) FetchFileUrl() string {
|
||||
}
|
||||
|
||||
func (self *SFile) Upload() error {
|
||||
req, _ := http.NewRequest(http.MethodPut, self.GetUrl(), self.File)
|
||||
req, _ := http.NewRequest(http.MethodPut, self.GetUrl(), self.file)
|
||||
req.Header.Add("Authorization", self.auth(http.MethodPut))
|
||||
req.Header.Add("Content-MD5", self.FileMD5)
|
||||
req.Header.Add("Content-MD5", self.Hash)
|
||||
req.Header.Add("Content-Type", "application/octet-stream")
|
||||
req.Header.Add("Content-Length", strconv.FormatInt(self.FileSize, 10))
|
||||
|
||||
return self.request(req)
|
||||
req.Header.Add("Content-Length", strconv.FormatInt(self.Size, 10))
|
||||
_, err := doRequest(req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SFile) Delete() error {
|
||||
req, _ := http.NewRequest(http.MethodDelete, self.GetUrl(), nil)
|
||||
req.Header.Add("Authorization", self.auth(http.MethodDelete))
|
||||
return self.request(req)
|
||||
_, err := doRequest(req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *SFile) request(req *http.Request) error {
|
||||
res, err := httputils.GetDefaultClient().Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (self *SFile) GetIBucket() cloudprovider.ICloudBucket {
|
||||
return self.bucket
|
||||
}
|
||||
|
||||
_, _, err = httputils.ParseJSONResponse(res, err, false)
|
||||
if err != nil {
|
||||
log.Errorf("SFile %s", err.Error())
|
||||
return err
|
||||
}
|
||||
func (self *SFile) GetKey() string {
|
||||
return self.FileName
|
||||
}
|
||||
|
||||
func (self *SFile) GetSizeBytes() int64 {
|
||||
return self.Size
|
||||
}
|
||||
|
||||
func (self *SFile) GetLastModified() time.Time {
|
||||
return time.Unix(self.ModifyTime, 0)
|
||||
}
|
||||
|
||||
func (self *SFile) GetStorageClass() string {
|
||||
return self.StorageClass
|
||||
}
|
||||
|
||||
func (self *SFile) GetETag() string {
|
||||
return self.Hash
|
||||
}
|
||||
|
||||
func (self *SFile) GetContentType() string {
|
||||
return self.MimeType
|
||||
}
|
||||
|
||||
func (self *SFile) GetAcl() cloudprovider.TBucketACLType {
|
||||
return cloudprovider.ACLDefault
|
||||
}
|
||||
|
||||
func (self *SFile) SetAcl(cloudprovider.TBucketACLType) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func doRequest(req *http.Request) (jsonutils.JSONObject, error) {
|
||||
res, err := httputils.GetDefaultClient().Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "httpclient Do")
|
||||
}
|
||||
_, body, err := httputils.ParseJSONResponse(res, err, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ParseJSONResponse")
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
type sPrefixFileListOutput struct {
|
||||
BucketName string
|
||||
BucketId string
|
||||
NextMarker string
|
||||
DataSet []SFile
|
||||
}
|
||||
|
||||
func (b *SBucket) doPrefixFileList(prefix string, marker string, limit int) (*sPrefixFileListOutput, error) {
|
||||
params := jsonutils.NewDict()
|
||||
params.Add(jsonutils.NewString(""), "list")
|
||||
if len(prefix) > 0 {
|
||||
params.Add(jsonutils.NewString(prefix), "prefix")
|
||||
}
|
||||
if len(marker) > 0 {
|
||||
params.Add(jsonutils.NewString(marker), "marker")
|
||||
}
|
||||
if limit > 0 {
|
||||
params.Add(jsonutils.NewInt(int64(limit)), "limit")
|
||||
}
|
||||
host := fmt.Sprintf("https://%s.ufile.ucloud.cn", b.BucketName)
|
||||
path := fmt.Sprintf("/?%s", params.QueryString())
|
||||
|
||||
log.Debugf("Request %s%s", host, path)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, host+path, nil)
|
||||
|
||||
sign := b.region.client.signHeader(http.MethodGet, path, "")
|
||||
auth := "UCloud" + " " + b.region.client.accessKeyId + ":" + sign
|
||||
|
||||
req.Header.Add("Authorization", auth)
|
||||
|
||||
output := sPrefixFileListOutput{}
|
||||
|
||||
body, err := doRequest(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "doRequest")
|
||||
}
|
||||
err = body.Unmarshal(&output)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "body.Unmarshal")
|
||||
}
|
||||
|
||||
return &output, nil
|
||||
}
|
||||
|
||||
func (b *SBucket) GetProjectId() string {
|
||||
return b.projectId
|
||||
return b.region.client.projectId
|
||||
}
|
||||
|
||||
func (b *SBucket) GetGlobalId() string {
|
||||
@@ -170,7 +252,7 @@ func (b *SBucket) GetName() string {
|
||||
}
|
||||
|
||||
func (b *SBucket) GetLocation() string {
|
||||
return b.Region
|
||||
return b.region.GetId()
|
||||
}
|
||||
|
||||
func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion {
|
||||
@@ -185,8 +267,21 @@ func (b *SBucket) GetStorageClass() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *SBucket) GetAcl() string {
|
||||
return b.Type
|
||||
func (b *SBucket) GetAcl() cloudprovider.TBucketACLType {
|
||||
switch b.Type {
|
||||
case "public":
|
||||
return cloudprovider.ACLPublicRead
|
||||
default:
|
||||
return cloudprovider.ACLPrivate
|
||||
}
|
||||
}
|
||||
|
||||
func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error {
|
||||
aclType := "private"
|
||||
if aclStr == cloudprovider.ACLPublicRead || aclStr == cloudprovider.ACLPublicReadWrite {
|
||||
aclType = "public"
|
||||
}
|
||||
return b.region.updateBucket(b.BucketName, aclType)
|
||||
}
|
||||
|
||||
func (b *SBucket) getSrcUrl() string {
|
||||
@@ -213,13 +308,34 @@ func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (b *SBucket) GetStats() cloudprovider.SBucketStats {
|
||||
stats, _ := cloudprovider.GetIBucketStats(b)
|
||||
return stats
|
||||
}
|
||||
|
||||
func (b *SBucket) GetIObjects(prefix string, isRecursive bool) ([]cloudprovider.ICloudObject, error) {
|
||||
return cloudprovider.GetIObjects(b, prefix, isRecursive)
|
||||
}
|
||||
|
||||
func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) {
|
||||
result := cloudprovider.SListObjectResult{}
|
||||
return result, cloudprovider.ErrNotSupported
|
||||
|
||||
output, err := b.doPrefixFileList(prefix, marker, maxCount)
|
||||
if err != nil {
|
||||
return result, errors.Wrap(err, "b.doPrefixFileList")
|
||||
}
|
||||
|
||||
if len(output.NextMarker) > 0 {
|
||||
result.NextMarker = output.NextMarker
|
||||
result.IsTruncated = true
|
||||
}
|
||||
|
||||
result.Objects = make([]cloudprovider.ICloudObject, len(output.DataSet))
|
||||
for i := range output.DataSet {
|
||||
result.Objects[i] = &output.DataSet[i]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, contType string, storageClassStr string) error {
|
||||
|
||||
@@ -119,6 +119,10 @@ func (self *SZStackProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, erro
|
||||
return self.client.GetSubAccounts()
|
||||
}
|
||||
|
||||
func (self *SZStackProvider) GetAccountId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self *SZStackProvider) GetIRegions() []cloudprovider.ICloudRegion {
|
||||
return self.client.GetIRegions()
|
||||
}
|
||||
@@ -138,3 +142,7 @@ func (self *SZStackProvider) GetCloudRegionExternalIdPrefix() string {
|
||||
func (self *SZStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) {
|
||||
return self.client.GetIProjects()
|
||||
}
|
||||
|
||||
func (self *SZStackProvider) GetStorageClasses(regionId string) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user