s3gateway phase2

This commit is contained in:
Qiu Jian
2019-07-28 14:07:47 +08:00
parent a7d8b931e9
commit fc7885b9f1
59 changed files with 2446 additions and 425 deletions
+48
View File
@@ -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
})
}
+17
View File
@@ -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
})
}
+32
View File
@@ -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
+2
View File
@@ -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"
+33
View File
@@ -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
+2
View File
@@ -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"
+24 -4
View File
@@ -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
}
+61 -1
View File
@@ -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 {
+1
View File
@@ -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
View File
@@ -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
}
+23 -2
View File
@@ -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()
+40
View File
@@ -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
}
+97 -2
View File
@@ -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
}
+45 -8
View File
@@ -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()
+44
View File
@@ -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",
}
}
+19 -35
View File
@@ -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
View File
@@ -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 {
+69 -7
View File
@@ -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")
}
+15
View File
@@ -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",
}
}
+17 -40
View File
@@ -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:]
+42 -1
View File
@@ -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
}
+73 -3
View File
@@ -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
}
+11 -1
View File
@@ -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
}
+2 -2
View File
@@ -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 {
+1 -1
View File
@@ -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
}
+14
View File
@@ -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
}
+13 -5
View File
@@ -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)
}
+144 -71
View File
@@ -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
+1 -1
View File
@@ -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
}
}
+33
View File
@@ -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
}
+4
View File
@@ -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
}
+8
View File
@@ -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
}
+90 -21
View File
@@ -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) {
+84 -3
View File
@@ -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 {
+38 -1
View File
@@ -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
}
+1 -1
View File
@@ -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",
}
}
+14 -34
View File
@@ -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) {
+4
View File
@@ -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 //////////
+13 -3
View File
@@ -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{
{
+19
View File
@@ -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
}
+160 -10
View File
@@ -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{}
}
+65 -2
View File
@@ -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
})
}
+125
View File
@@ -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
}
+4
View File
@@ -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
}
+68 -6
View File
@@ -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)
}
+37 -1
View File
@@ -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",
}
}
+112 -2
View File
@@ -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 {
+11 -51
View File
@@ -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",
}
}
+27 -26
View File
@@ -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)
}
+17 -6
View File
@@ -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
+87 -1
View 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
View File
@@ -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
}