yunion.io/x/cloudmux@v0.3.10-0-alpha.1/cmd/cmx/shell/objectstore.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package shell
    16  
    17  import (
    18  	// "context"
    19  	// "fmt"
    20  	// "io"
    21  	// "mime"
    22  	"net/http"
    23  	// "os"
    24  	// "path/filepath"
    25  	"strings"
    26  	// "time"
    27  
    28  	// "yunion.io/x/onecloud/pkg/util/fileutils2"
    29  	// "yunion.io/x/onecloud/pkg/util/streamutils"
    30  	// "yunion.io/x/pkg/errors"
    31  
    32  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    33  )
    34  
    35  type ObjectHeaderOptions struct {
    36  	CacheControl       string `help:"Cache-Control"`
    37  	ContentType        string `help:"Content-Type"`
    38  	ContentEncoding    string `help:"Content-Encoding"`
    39  	ContentLanguage    string `help:"Content-Language"`
    40  	ContentDisposition string `help:"Content-Disposition"`
    41  	ContentMD5         string `help:"Content-MD5"`
    42  
    43  	Meta []string `help:"header, common seperatored key and value, e.g. max-age:100"`
    44  }
    45  
    46  func (args ObjectHeaderOptions) Options2Header() http.Header {
    47  	meta := http.Header{}
    48  	for _, kv := range args.Meta {
    49  		parts := strings.Split(kv, ":")
    50  		if len(parts) == 2 {
    51  			key := strings.TrimSpace(parts[0])
    52  			value := strings.TrimSpace(parts[1])
    53  			if len(key) > 0 && len(value) > 0 {
    54  				meta.Add(key, value)
    55  			}
    56  		}
    57  	}
    58  	if len(args.CacheControl) > 0 {
    59  		meta.Set(cloudprovider.META_HEADER_CACHE_CONTROL, args.CacheControl)
    60  	}
    61  	if len(args.ContentType) > 0 {
    62  		meta.Set(cloudprovider.META_HEADER_CONTENT_TYPE, args.ContentType)
    63  	}
    64  	if len(args.ContentEncoding) > 0 {
    65  		meta.Set(cloudprovider.META_HEADER_CONTENT_ENCODING, args.ContentEncoding)
    66  	}
    67  	if len(args.ContentMD5) > 0 {
    68  		meta.Set(cloudprovider.META_HEADER_CONTENT_MD5, args.ContentMD5)
    69  	}
    70  	if len(args.ContentLanguage) > 0 {
    71  		meta.Set(cloudprovider.META_HEADER_CONTENT_LANGUAGE, args.ContentLanguage)
    72  	}
    73  	if len(args.ContentDisposition) > 0 {
    74  		meta.Set(cloudprovider.META_HEADER_CONTENT_DISPOSITION, args.ContentDisposition)
    75  	}
    76  	return meta
    77  }
    78  
    79  func init() {
    80  	cmd := NewCommand("bucket")
    81  
    82  	eR := EmptyOptionRegionR("bucket")
    83  
    84  	eR.GetterList("list", "List all bucket", func(ir cloudprovider.ICloudRegion) (any, error) {
    85  		return ir.GetIBuckets()
    86  	})
    87  
    88  	type BucketCreateOptions struct {
    89  		NAME         string `help:"name of bucket to create"`
    90  		Acl          string `help:"ACL string" choices:"private|public-read|public-read-write"`
    91  		StorageClass string `help:"StorageClass"`
    92  	}
    93  	RegionR[BucketCreateOptions](cmd).Run("create", "Create bucket", func(cli cloudprovider.ICloudRegion, args *BucketCreateOptions) (any, error) {
    94  		return nil, cli.CreateIBucket(args.NAME, args.StorageClass, args.Acl)
    95  	})
    96  
    97  	type BucketAclOptions struct {
    98  		BUCKET string `help:"name of bucket"`
    99  		ACL    string `help:"ACL string" choices:"private|public-read|public-read-write"`
   100  	}
   101  	RegionR[BucketAclOptions](cmd).Run("set-acl", "Set bucket ACL", func(cli cloudprovider.ICloudRegion, args *BucketAclOptions) (any, error) {
   102  		bucket, err := cli.GetIBucketById(args.BUCKET)
   103  		if err != nil {
   104  			return nil, err
   105  		}
   106  		err = bucket.SetAcl(cloudprovider.TBucketACLType(args.ACL))
   107  		if err != nil {
   108  			return nil, err
   109  		}
   110  		return nil, nil
   111  	})
   112  
   113  	// type BucketDeleteOptions struct {
   114  	// 	NAME string `help:"name of bucket to delete"`
   115  	// }
   116  	// RegionR(&BucketDeleteOptions{}, "bucket-delete", "Delete bucket", func(cli cloudprovider.ICloudRegion, args *BucketDeleteOptions) error {
   117  	// 	err := cli.DeleteIBucket(args.NAME)
   118  	// 	if err != nil {
   119  	// 		return err
   120  	// 	}
   121  	// 	return nil
   122  	// })
   123  	//
   124  	// type BucketLimitOptions struct {
   125  	// 	NAME    string `help:"name of bucket to set limit"`
   126  	// 	SizeGB  int    `help:"limit of volumes in GB"`
   127  	// 	Objects int    `help:"limit of object count"`
   128  	// 	Off     bool   `help:"Turn off limit"`
   129  	// }
   130  	// RegionR(&BucketLimitOptions{}, "bucket-set-limit", "Set bucket limit", func(cli cloudprovider.ICloudRegion, args *BucketLimitOptions) error {
   131  	// 	bucket, err := cli.GetIBucketByName(args.NAME)
   132  	// 	if err != nil {
   133  	// 		return err
   134  	// 	}
   135  	// 	if args.Off {
   136  	// 		err = bucket.SetLimit(cloudprovider.SBucketStats{})
   137  	// 	} else {
   138  	// 		fmt.Println("set limit")
   139  	// 		err = bucket.SetLimit(cloudprovider.SBucketStats{SizeBytes: int64(args.SizeGB * 1000 * 1000 * 1000), ObjectCount: args.Objects})
   140  	// 	}
   141  	// 	if err != nil {
   142  	// 		return err
   143  	// 	}
   144  	// 	return nil
   145  	// })
   146  	//
   147  	// type BucketExistOptions struct {
   148  	// 	NAME string `help:"name of bucket to delete"`
   149  	// }
   150  	// RegionR(&BucketExistOptions{}, "bucket-exist", "Test existence of a bucket", func(cli cloudprovider.ICloudRegion, args *BucketExistOptions) error {
   151  	// 	exist, err := cli.IBucketExist(args.NAME)
   152  	// 	if err != nil {
   153  	// 		return err
   154  	// 	}
   155  	// 	fmt.Printf("Exist: %v\n", exist)
   156  	// 	return nil
   157  	// })
   158  	//
   159  	// type BucketObjectsOptions struct {
   160  	// 	BUCKET    string `help:"name of bucket to list objects"`
   161  	// 	Prefix    string `help:"prefix"`
   162  	// 	Marker    string `help:"marker"`
   163  	// 	Demiliter string `help:"delimiter"`
   164  	// 	Max       int    `help:"Max count"`
   165  	// }
   166  	// RegionR(&BucketObjectsOptions{}, "bucket-object", "List objects in a bucket", func(cli cloudprovider.ICloudRegion, args *BucketObjectsOptions) error {
   167  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   168  	// 	if err != nil {
   169  	// 		return err
   170  	// 	}
   171  	// 	result, err := bucket.ListObjects(args.Prefix, args.Marker, args.Demiliter, args.Max)
   172  	// 	if err != nil {
   173  	// 		return err
   174  	// 	}
   175  	// 	if result.IsTruncated {
   176  	// 		fmt.Printf("NextMarker: %s IsTruncated: %v\n", result.NextMarker, result.IsTruncated)
   177  	// 	}
   178  	// 	fmt.Println("Common prefixes:")
   179  	// 	PrintGetterList(result.CommonPrefixes, []string{"key", "size_bytes"})
   180  	// 	fmt.Println("Objects:")
   181  	// 	PrintGetterList(result.Objects, []string{"key", "size_bytes"})
   182  	// 	return nil
   183  	// })
   184  	//
   185  	// type BucketListObjectsOptions struct {
   186  	// 	BUCKET string `help:"name of bucket to list objects"`
   187  	// 	Prefix string `help:"prefix"`
   188  	// 	Limit  int    `help:"limit per page request" default:"20"`
   189  	// 	Marker string `help:"offset marker"`
   190  	// }
   191  	// RegionR(&BucketListObjectsOptions{}, "bucket-list-object", "List objects in a bucket", func(cli cloudprovider.ICloudRegion, args *BucketListObjectsOptions) error {
   192  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   193  	// 	if err != nil {
   194  	// 		return err
   195  	// 	}
   196  	// 	objects, marker, err := cloudprovider.GetPagedObjects(bucket, args.Prefix, true, args.Marker, args.Limit)
   197  	// 	if err != nil {
   198  	// 		return err
   199  	// 	}
   200  	// 	PrintGetterList(objects, []string{"key", "size_bytes"})
   201  	// 	if len(marker) > 0 {
   202  	// 		fmt.Println("Next marker:", marker)
   203  	// 	}
   204  	// 	return nil
   205  	// })
   206  	//
   207  	// RegionR(&BucketListObjectsOptions{}, "bucket-dir-object", "List objects in a bucket like directory", func(cli cloudprovider.ICloudRegion, args *BucketListObjectsOptions) error {
   208  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   209  	// 	if err != nil {
   210  	// 		return err
   211  	// 	}
   212  	// 	objects, marker, err := cloudprovider.GetPagedObjects(bucket, args.Prefix, false, args.Marker, args.Limit)
   213  	// 	if err != nil {
   214  	// 		return err
   215  	// 	}
   216  	// 	PrintGetterList(objects, []string{"key", "size_bytes"})
   217  	// 	if len(marker) > 0 {
   218  	// 		fmt.Println("Next marker:", marker)
   219  	// 	}
   220  	// 	return nil
   221  	// })
   222  	//
   223  	// type BucketMakrdirOptions struct {
   224  	// 	BUCKET string `help:"name of bucket to put object"`
   225  	// 	DIR    string `help:"dir to make"`
   226  	// }
   227  	// RegionR(&BucketMakrdirOptions{}, "bucket-mkdir", "Mkdir in a bucket", func(cli cloudprovider.ICloudRegion, args *BucketMakrdirOptions) error {
   228  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   229  	// 	if err != nil {
   230  	// 		return err
   231  	// 	}
   232  	// 	err = cloudprovider.Makedir(context.Background(), bucket, args.DIR)
   233  	// 	if err != nil {
   234  	// 		return err
   235  	// 	}
   236  	// 	fmt.Printf("Mkdir success\n")
   237  	// 	return nil
   238  	// })
   239  	//
   240  	// type BucketPutObjectOptions struct {
   241  	// 	BUCKET string `help:"name of bucket to put object"`
   242  	// 	KEY    string `help:"key of object"`
   243  	// 	Path   string `help:"Path of file to upload"`
   244  	//
   245  	// 	BlockSize int64 `help:"blocksz in MB" default:"100"`
   246  	//
   247  	// 	Acl string `help:"acl" choices:"private|public-read|public-read-write"`
   248  	//
   249  	// 	StorageClass string `help:"storage class"`
   250  	//
   251  	// 	ObjectHeaderOptions
   252  	// }
   253  	// RegionR(&BucketPutObjectOptions{}, "put-object", "Put object into a bucket", func(cli cloudprovider.ICloudRegion, args *BucketPutObjectOptions) error {
   254  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   255  	// 	if err != nil {
   256  	// 		return err
   257  	// 	}
   258  	//
   259  	// 	originMeta := args.ObjectHeaderOptions.Options2Header()
   260  	//
   261  	// 	if len(args.Path) > 0 {
   262  	// 		uploadFile := func(key, path string) error {
   263  	// 			meta := http.Header{}
   264  	// 			for k, v := range originMeta {
   265  	// 				meta[k] = v
   266  	// 			}
   267  	//
   268  	// 			finfo, err := os.Stat(path)
   269  	// 			if err != nil {
   270  	// 				return errors.Wrap(err, "os.Stat")
   271  	// 			}
   272  	// 			fSize := finfo.Size()
   273  	// 			file, err := os.Open(path)
   274  	// 			if err != nil {
   275  	// 				return errors.Wrap(err, "os.Open")
   276  	// 			}
   277  	// 			defer file.Close()
   278  	//
   279  	// 			if contTypes, ok := meta[cloudprovider.META_HEADER_CONTENT_TYPE]; !ok || len(contTypes) == 0 {
   280  	// 				var ext string
   281  	// 				lastSlashPos := strings.LastIndex(path, "/")
   282  	// 				lastExtPos := strings.LastIndex(path, ".")
   283  	// 				if lastExtPos >= 0 && lastExtPos > lastSlashPos {
   284  	// 					ext = path[lastExtPos:]
   285  	// 				}
   286  	// 				if len(ext) > 0 {
   287  	// 					contType := mime.TypeByExtension(ext)
   288  	// 					meta.Set(cloudprovider.META_HEADER_CONTENT_TYPE, contType)
   289  	// 				}
   290  	// 			}
   291  	//
   292  	// 			err = cloudprovider.UploadObject(context.Background(), bucket, key, args.BlockSize*1000*1000, file, fSize, cloudprovider.TBucketACLType(args.Acl), args.StorageClass, meta, true)
   293  	// 			if err != nil {
   294  	// 				return err
   295  	// 			}
   296  	//
   297  	// 			return nil
   298  	// 		}
   299  	// 		if fileutils2.IsFile(args.Path) {
   300  	// 			err := uploadFile(args.KEY, args.Path)
   301  	// 			if err != nil {
   302  	// 				return errors.Wrap(err, "uploadFile")
   303  	// 			}
   304  	// 		} else if fileutils2.IsDir(args.Path) {
   305  	// 			return filepath.Walk(args.Path, func(path string, info os.FileInfo, err error) error {
   306  	// 				if err != nil {
   307  	// 					return err
   308  	// 				}
   309  	// 				if info.Mode().IsRegular() {
   310  	// 					rel, _ := filepath.Rel(args.Path, path)
   311  	// 					src := path
   312  	// 					dst := filepath.Join(args.KEY, rel)
   313  	// 					fmt.Println("upload", src, "to", dst)
   314  	// 					uploadErr := uploadFile(dst, src)
   315  	// 					if uploadErr != nil {
   316  	// 						return uploadErr
   317  	// 					}
   318  	// 				}
   319  	// 				return nil
   320  	// 			})
   321  	// 		}
   322  	// 	} else {
   323  	// 		err = cloudprovider.UploadObject(context.Background(), bucket, args.KEY, args.BlockSize*1000*1000, os.Stdin, 0, cloudprovider.TBucketACLType(args.Acl), args.StorageClass, originMeta, true)
   324  	// 		if err != nil {
   325  	// 			return err
   326  	// 		}
   327  	// 	}
   328  	//
   329  	// 	fmt.Printf("Upload success\n")
   330  	// 	return nil
   331  	// })
   332  	//
   333  	// type BucketDeleteObjectOptions struct {
   334  	// 	BUCKET string `help:"name of bucket to put object"`
   335  	// 	KEY    string `help:"key of object"`
   336  	// }
   337  	// RegionR(&BucketDeleteObjectOptions{}, "delete-object", "Delete object from a bucket", func(cli cloudprovider.ICloudRegion, args *BucketDeleteObjectOptions) error {
   338  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   339  	// 	if err != nil {
   340  	// 		return err
   341  	// 	}
   342  	// 	err = bucket.DeleteObject(context.Background(), args.KEY)
   343  	// 	if err != nil {
   344  	// 		return err
   345  	// 	}
   346  	// 	fmt.Printf("Delete success\n")
   347  	// 	return nil
   348  	// })
   349  	//
   350  	// RegionR(&BucketDeleteObjectOptions{}, "delete-prefix", "Delete object from a bucket", func(cli cloudprovider.ICloudRegion, args *BucketDeleteObjectOptions) error {
   351  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   352  	// 	if err != nil {
   353  	// 		return err
   354  	// 	}
   355  	// 	err = cloudprovider.DeletePrefix(context.Background(), bucket, args.KEY)
   356  	// 	if err != nil {
   357  	// 		return err
   358  	// 	}
   359  	// 	fmt.Printf("Delete success\n")
   360  	// 	return nil
   361  	// })
   362  	//
   363  	// type BucketTempUrlOption struct {
   364  	// 	BUCKET   string `help:"name of bucket to put object"`
   365  	// 	METHOD   string `help:"http method" choices:"GET|PUT|DELETE"`
   366  	// 	KEY      string `help:"key of object"`
   367  	// 	Duration int    `help:"duration in seconds" default:"60"`
   368  	// }
   369  	// RegionR(&BucketTempUrlOption{}, "temp-url", "generate temp url", func(cli cloudprovider.ICloudRegion, args *BucketTempUrlOption) error {
   370  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   371  	// 	if err != nil {
   372  	// 		return err
   373  	// 	}
   374  	// 	urlStr, err := bucket.GetTempUrl(args.METHOD, args.KEY, time.Duration(args.Duration)*time.Second)
   375  	// 	if err != nil {
   376  	// 		return err
   377  	// 	}
   378  	// 	fmt.Println(urlStr)
   379  	// 	return nil
   380  	// })
   381  	//
   382  	// type BucketAclOption struct {
   383  	// 	BUCKET string `help:"name of bucket to put object"`
   384  	// 	KEY    string `help:"key of object"`
   385  	// }
   386  	// RegionR(&BucketAclOption{}, "object-acl", "Get object acl", func(cli cloudprovider.ICloudRegion, args *BucketAclOption) error {
   387  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   388  	// 	if err != nil {
   389  	// 		return err
   390  	// 	}
   391  	// 	object, err := cloudprovider.GetIObject(bucket, args.KEY)
   392  	// 	if err != nil {
   393  	// 		return err
   394  	// 	}
   395  	// 	fmt.Println(object.GetAcl())
   396  	// 	return nil
   397  	// })
   398  	//
   399  	// type BucketSetAclOption struct {
   400  	// 	BUCKET string `help:"name of bucket to put object"`
   401  	// 	KEY    string `help:"key of object"`
   402  	// 	ACL    string `help:"Target acl" choices:"default|private|public-read|public-read-write"`
   403  	// }
   404  	// RegionR(&BucketSetAclOption{}, "object-set-acl", "Get object acl", func(cli cloudprovider.ICloudRegion, args *BucketSetAclOption) error {
   405  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   406  	// 	if err != nil {
   407  	// 		return err
   408  	// 	}
   409  	// 	object, err := cloudprovider.GetIObject(bucket, args.KEY)
   410  	// 	if err != nil {
   411  	// 		return err
   412  	// 	}
   413  	// 	err = object.SetAcl(cloudprovider.TBucketACLType(args.ACL))
   414  	// 	if err != nil {
   415  	// 		return err
   416  	// 	}
   417  	// 	fmt.Println("Success!")
   418  	// 	return nil
   419  	// })
   420  	//
   421  	// type BucketSetWebsiteOption struct {
   422  	// 	BUCKET string `help:"name of bucket to put object"`
   423  	// 	// 主页
   424  	// 	Index string `help:"main page"`
   425  	// 	// 错误时返回的文档
   426  	// 	ErrorDocument string `help:"error return"`
   427  	// 	// http或https
   428  	// 	Protocol string `help:"force https" choices:"http|https"`
   429  	// }
   430  	// RegionR(&BucketSetWebsiteOption{}, "bucket-set-website", "Set bucket website", func(cli cloudprovider.ICloudRegion, args *BucketSetWebsiteOption) error {
   431  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   432  	// 	if err != nil {
   433  	// 		return err
   434  	// 	}
   435  	// 	conf := cloudprovider.SBucketWebsiteConf{
   436  	// 		Index:         args.Index,
   437  	// 		ErrorDocument: args.ErrorDocument,
   438  	// 		Protocol:      args.Protocol,
   439  	// 	}
   440  	// 	err = bucket.SetWebsite(conf)
   441  	// 	if err != nil {
   442  	// 		return err
   443  	// 	}
   444  	// 	fmt.Println("Success!")
   445  	// 	return nil
   446  	// })
   447  	//
   448  	// type BucketGetWebsiteConfOption struct {
   449  	// 	BUCKET string `help:"name of bucket to put object"`
   450  	// }
   451  	// RegionR(&BucketGetWebsiteConfOption{}, "bucket-get-website", "Get bucket website", func(cli cloudprovider.ICloudRegion, args *BucketGetWebsiteConfOption) error {
   452  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   453  	// 	if err != nil {
   454  	// 		return err
   455  	// 	}
   456  	// 	conf, err := bucket.GetWebsiteConf()
   457  	// 	if err != nil {
   458  	// 		return err
   459  	// 	}
   460  	// 	PrintObject(conf)
   461  	// 	return nil
   462  	// })
   463  	//
   464  	// type BucketDeleteWebsiteConfOption struct {
   465  	// 	BUCKET string `help:"name of bucket to put object"`
   466  	// }
   467  	// RegionR(&BucketDeleteWebsiteConfOption{}, "bucket-delete-website", "Delete bucket website", func(cli cloudprovider.ICloudRegion, args *BucketDeleteWebsiteConfOption) error {
   468  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   469  	// 	if err != nil {
   470  	// 		return err
   471  	// 	}
   472  	// 	err = bucket.DeleteWebSiteConf()
   473  	// 	if err != nil {
   474  	// 		return err
   475  	// 	}
   476  	// 	fmt.Println("Success!")
   477  	// 	return nil
   478  	// })
   479  	//
   480  	// type BucketSetCorsOption struct {
   481  	// 	BUCKET         string `help:"name of bucket to put object"`
   482  	// 	AllowedMethods []string
   483  	// 	// 允许的源站,可以设为*
   484  	// 	AllowedOrigins []string
   485  	// 	AllowedHeaders []string
   486  	// 	MaxAgeSeconds  int
   487  	// 	ExposeHeaders  []string
   488  	// 	Id             string
   489  	// }
   490  	// RegionR(&BucketSetCorsOption{}, "bucket-set-cors", "Set bucket cors", func(cli cloudprovider.ICloudRegion, args *BucketSetCorsOption) error {
   491  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   492  	// 	if err != nil {
   493  	// 		return err
   494  	// 	}
   495  	// 	rule := cloudprovider.SBucketCORSRule{
   496  	// 		AllowedOrigins: args.AllowedOrigins,
   497  	// 		AllowedMethods: args.AllowedMethods,
   498  	// 		AllowedHeaders: args.AllowedHeaders,
   499  	// 		MaxAgeSeconds:  args.MaxAgeSeconds,
   500  	// 		ExposeHeaders:  args.ExposeHeaders,
   501  	// 		Id:             args.Id,
   502  	// 	}
   503  	// 	err = cloudprovider.SetBucketCORS(bucket, []cloudprovider.SBucketCORSRule{rule})
   504  	// 	if err != nil {
   505  	// 		return err
   506  	// 	}
   507  	// 	fmt.Println("Success!")
   508  	// 	return nil
   509  	// })
   510  	//
   511  	// type BucketGetCorsOption struct {
   512  	// 	BUCKET string `help:"name of bucket to put object"`
   513  	// }
   514  	// RegionR(&BucketGetCorsOption{}, "bucket-get-cors", "Get bucket cors", func(cli cloudprovider.ICloudRegion, args *BucketGetCorsOption) error {
   515  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   516  	// 	if err != nil {
   517  	// 		return err
   518  	// 	}
   519  	// 	rules, err := bucket.GetCORSRules()
   520  	// 	if err != nil {
   521  	// 		return err
   522  	// 	}
   523  	// 	PrintList(rules, len(rules), 0, len(rules), nil)
   524  	// 	return nil
   525  	// })
   526  	//
   527  	// type BucketDeleteCorsOption struct {
   528  	// 	BUCKET string   `help:"name of bucket to put object"`
   529  	// 	Ids    []string `help:"rule ids to delete"`
   530  	// }
   531  	// RegionR(&BucketDeleteCorsOption{}, "bucket-delete-cors", "Delete bucket cors", func(cli cloudprovider.ICloudRegion, args *BucketDeleteCorsOption) error {
   532  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   533  	// 	if err != nil {
   534  	// 		return err
   535  	// 	}
   536  	// 	result, err := cloudprovider.DeleteBucketCORS(bucket, args.Ids)
   537  	// 	if err != nil {
   538  	// 		return err
   539  	// 	}
   540  	// 	PrintList(result, len(result), 0, len(result), nil)
   541  	// 	fmt.Println("Success!")
   542  	// 	return nil
   543  	// })
   544  	//
   545  	// type BucketSetRefererOption struct {
   546  	// 	BUCKET      string `help:"name of bucket to put object"`
   547  	// 	RefererType string `help:"referer type" choices:"Black-List|White-List" default:"Black-List"`
   548  	// 	DomainList  []string
   549  	// 	// 是否允许空refer 访问
   550  	// 	AllowEmptyRefer bool `help:"all empty refer access"`
   551  	// 	Disable         bool
   552  	// }
   553  	// RegionR(&BucketSetRefererOption{}, "bucket-set-referer", "Set bucket referer", func(cli cloudprovider.ICloudRegion, args *BucketSetRefererOption) error {
   554  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   555  	// 	if err != nil {
   556  	// 		return err
   557  	// 	}
   558  	// 	conf := cloudprovider.SBucketRefererConf{
   559  	// 		DomainList:      args.DomainList,
   560  	// 		RefererType:     args.RefererType,
   561  	// 		AllowEmptyRefer: args.AllowEmptyRefer,
   562  	// 		Enabled:         true,
   563  	// 	}
   564  	// 	if args.Disable {
   565  	// 		conf.Enabled = false
   566  	// 	}
   567  	// 	err = bucket.SetReferer(conf)
   568  	// 	if err != nil {
   569  	// 		return err
   570  	// 	}
   571  	// 	fmt.Println("Success!")
   572  	// 	return nil
   573  	//
   574  	// })
   575  	//
   576  	// type BucketGetPolicyOption struct {
   577  	// 	BUCKET string `help:"name of bucket to put object"`
   578  	// }
   579  	// RegionR(&BucketGetPolicyOption{}, "bucket-get-policy", "get bucket policy", func(cli cloudprovider.ICloudRegion, args *BucketGetPolicyOption) error {
   580  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   581  	// 	if err != nil {
   582  	// 		return err
   583  	// 	}
   584  	// 	policy, err := bucket.GetPolicy()
   585  	// 	if err != nil {
   586  	// 		return err
   587  	// 	}
   588  	// 	PrintList(policy, len(policy), 0, len(policy), nil)
   589  	// 	return nil
   590  	// })
   591  	//
   592  	// type BucketSetPolicyOption struct {
   593  	// 	BUCKET string `help:"name of bucket to put object"`
   594  	// 	// 格式主账号id:子账号id
   595  	// 	PrincipalId []string
   596  	// 	// Read|ReadWrite|FullControl
   597  	// 	CannedAction string
   598  	// 	// Allow|Deny
   599  	// 	Effect string
   600  	// 	// 被授权的资源地址
   601  	// 	ResourcePath []string
   602  	// 	// ip 条件
   603  	// 	IpEquals    []string
   604  	// 	IpNotEquals []string
   605  	// }
   606  	// RegionR(&BucketSetPolicyOption{}, "bucket-set-policy", "set bucket policy", func(cli cloudprovider.ICloudRegion, args *BucketSetPolicyOption) error {
   607  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   608  	// 	if err != nil {
   609  	// 		return err
   610  	// 	}
   611  	// 	opts := cloudprovider.SBucketPolicyStatementInput{}
   612  	// 	opts.CannedAction = args.CannedAction
   613  	// 	opts.Effect = args.Effect
   614  	// 	opts.IpEquals = args.IpEquals
   615  	// 	opts.IpNotEquals = args.IpNotEquals
   616  	// 	opts.ResourcePath = args.ResourcePath
   617  	// 	opts.PrincipalId = args.PrincipalId
   618  	//
   619  	// 	err = bucket.SetPolicy(opts)
   620  	// 	if err != nil {
   621  	// 		return err
   622  	// 	}
   623  	// 	return nil
   624  	// })
   625  	//
   626  	// type BucketDeletePolicyOption struct {
   627  	// 	BUCKET string `help:"name of bucket to put object"`
   628  	// 	Id     []string
   629  	// }
   630  	// RegionR(&BucketDeletePolicyOption{}, "bucket-delete-policy", "delete bucket policy", func(cli cloudprovider.ICloudRegion, args *BucketDeletePolicyOption) error {
   631  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   632  	// 	if err != nil {
   633  	// 		return err
   634  	// 	}
   635  	// 	result, err := bucket.DeletePolicy(args.Id)
   636  	// 	if err != nil {
   637  	// 		return err
   638  	// 	}
   639  	// 	PrintList(result, len(result), 0, len(result), nil)
   640  	// 	return nil
   641  	// })
   642  	//
   643  	// type BucketGetRefererOption struct {
   644  	// 	BUCKET string `help:"name of bucket to put object"`
   645  	// }
   646  	// RegionR(&BucketGetRefererOption{}, "bucket-get-referer", "get bucket referer", func(cli cloudprovider.ICloudRegion, args *BucketGetRefererOption) error {
   647  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   648  	// 	if err != nil {
   649  	// 		return err
   650  	// 	}
   651  	// 	conf, err := bucket.GetReferer()
   652  	// 	if err != nil {
   653  	// 		return err
   654  	// 	}
   655  	// 	PrintObject(conf)
   656  	// 	return nil
   657  	// })
   658  	//
   659  	// type BucketGetCdnDomainOption struct {
   660  	// 	BUCKET string `help:"name of bucket to put object"`
   661  	// }
   662  	// RegionR(&BucketGetCdnDomainOption{}, "bucket-get-cdn-domains", "get bucket cdn domains", func(cli cloudprovider.ICloudRegion, args *BucketGetCdnDomainOption) error {
   663  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   664  	// 	if err != nil {
   665  	// 		return err
   666  	// 	}
   667  	// 	domains, err := bucket.GetCdnDomains()
   668  	// 	if err != nil {
   669  	// 		return err
   670  	// 	}
   671  	// 	PrintList(domains, len(domains), 0, len(domains), nil)
   672  	// 	return nil
   673  	// })
   674  	//
   675  	// type BucketGetMetadata struct {
   676  	// 	BUCKET string `help:"name of bucket to put object"`
   677  	// }
   678  	// RegionR(&BucketGetMetadata{}, "bucket-tag-list", "List bucket tag", func(cli cloudprovider.ICloudRegion, args *BucketGetMetadata) error {
   679  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   680  	// 	if err != nil {
   681  	// 		return err
   682  	// 	}
   683  	// 	meta, err := bucket.GetTags()
   684  	// 	if err != nil {
   685  	// 		return err
   686  	// 	}
   687  	// 	PrintObject(meta)
   688  	// 	return nil
   689  	// })
   690  	//
   691  	// type BucketSetMetadate struct {
   692  	// 	BUCKET  string   `help:"name of bucket to put object"`
   693  	// 	Tags    []string `help:"Tags info, eg: hypervisor=aliyun、os_type=Linux、os_version"`
   694  	// 	Replace bool
   695  	// }
   696  	// RegionR(&BucketSetMetadate{}, "bucket-set-tag", "set bucket tag", func(cli cloudprovider.ICloudRegion, args *BucketSetMetadate) error {
   697  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   698  	// 	if err != nil {
   699  	// 		return err
   700  	// 	}
   701  	// 	tags := map[string]string{}
   702  	// 	for _, tag := range args.Tags {
   703  	// 		pair := strings.Split(tag, "=")
   704  	// 		if len(pair) == 2 {
   705  	// 			tags[pair[0]] = pair[1]
   706  	// 		}
   707  	// 	}
   708  	// 	_, err = cloudprovider.SetBucketTags(context.Background(), bucket, "", tags)
   709  	// 	if err != nil {
   710  	// 		return err
   711  	// 	}
   712  	// 	fmt.Println("Success!")
   713  	// 	return nil
   714  	// })
   715  	//
   716  	// type BucketGetUploads struct {
   717  	// 	BUCKET string `help:"name of bucket to put object"`
   718  	// }
   719  	// RegionR(&BucketGetUploads{}, "bucket-get-uploads", "get bucket uploads", func(cli cloudprovider.ICloudRegion, args *BucketGetUploads) error {
   720  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   721  	// 	if err != nil {
   722  	// 		return err
   723  	// 	}
   724  	// 	uplaods, err := bucket.ListMultipartUploads()
   725  	// 	PrintList(uplaods, len(uplaods), 0, len(uplaods), nil)
   726  	// 	return nil
   727  	// })
   728  	//
   729  	// type BucketObjectDownloadOptions struct {
   730  	// 	BUCKET string `help:"name of bucket"`
   731  	// 	KEY    string `help:"Key of object"`
   732  	// 	Output string `help:"target output, default to stdout"`
   733  	// 	Start  int64  `help:"partial download start"`
   734  	// 	End    int64  `help:"partial download end"`
   735  	// }
   736  	// RegionR(&BucketObjectDownloadOptions{}, "object-download", "Download", func(cli cloudprovider.ICloudRegion, args *BucketObjectDownloadOptions) error {
   737  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   738  	// 	if err != nil {
   739  	// 		return err
   740  	// 	}
   741  	// 	obj, err := cloudprovider.GetIObject(bucket, args.KEY)
   742  	// 	if err != nil {
   743  	// 		return err
   744  	// 	}
   745  	//
   746  	// 	var rangeOpt *cloudprovider.SGetObjectRange
   747  	// 	if args.Start != 0 || args.End != 0 {
   748  	// 		if args.End <= 0 {
   749  	// 			args.End = obj.GetSizeBytes() - 1
   750  	// 		}
   751  	// 		rangeOpt = &cloudprovider.SGetObjectRange{Start: args.Start, End: args.End}
   752  	// 	}
   753  	// 	output, err := bucket.GetObject(context.Background(), args.KEY, rangeOpt)
   754  	// 	if err != nil {
   755  	// 		return err
   756  	// 	}
   757  	// 	defer output.Close()
   758  	// 	var target io.Writer
   759  	// 	if len(args.Output) == 0 {
   760  	// 		target = os.Stdout
   761  	// 	} else {
   762  	// 		fp, err := os.Create(args.Output)
   763  	// 		if err != nil {
   764  	// 			return err
   765  	// 		}
   766  	// 		defer fp.Close()
   767  	// 		target = fp
   768  	// 	}
   769  	// 	prop, err := streamutils.StreamPipe(output, target, false, nil)
   770  	// 	if err != nil {
   771  	// 		return err
   772  	// 	}
   773  	// 	if len(args.Output) > 0 {
   774  	// 		fmt.Println("Success:", prop.Size, "written")
   775  	// 	}
   776  	// 	return nil
   777  	// })
   778  	//
   779  	// type BucketObjectTempUrlOptions struct {
   780  	// 	BUCKET string `help:"name of bucket"`
   781  	// 	KEY    string `help:"Key of object"`
   782  	// 	Method string `default:"GET" choices:"GET|PUT|POST"`
   783  	// 	Hour   int64  `default:"1"`
   784  	// }
   785  	//
   786  	// RegionR(&BucketObjectTempUrlOptions{}, "object-temp-url", "Show object temp url", func(cli cloudprovider.ICloudRegion, args *BucketObjectTempUrlOptions) error {
   787  	// 	bucket, err := cli.GetIBucketById(args.BUCKET)
   788  	// 	if err != nil {
   789  	// 		return err
   790  	// 	}
   791  	// 	url, err := bucket.GetTempUrl(args.Method, args.KEY, time.Duration(args.Hour)*time.Hour)
   792  	// 	if err != nil {
   793  	// 		return err
   794  	// 	}
   795  	// 	fmt.Println(url)
   796  	// 	return nil
   797  	// })
   798  	//
   799  	// type BucketObjectCopyOptions struct {
   800  	// 	SRC       string `help:"name of source bucket"`
   801  	// 	SRCKEY    string `help:"Key of source object"`
   802  	// 	DST       string `help:"name of destination bucket"`
   803  	// 	DSTKEY    string `help:"key of destination object"`
   804  	// 	Debug     bool   `help:"show debug info"`
   805  	// 	BlockSize int64  `help:"block size in MB"`
   806  	// 	Native    bool   `help:"Use native copy"`
   807  	//
   808  	// 	ObjectHeaderOptions
   809  	// }
   810  	// RegionR(&BucketObjectCopyOptions{}, "object-copy", "Copy object", func(cli cloudprovider.ICloudRegion, args *BucketObjectCopyOptions) error {
   811  	// 	ctx := context.Background()
   812  	// 	dstBucket, err := cli.GetIBucketByName(args.DST)
   813  	// 	if err != nil {
   814  	// 		return err
   815  	// 	}
   816  	// 	srcBucket, err := cli.GetIBucketByName(args.SRC)
   817  	// 	if err != nil {
   818  	// 		return err
   819  	// 	}
   820  	// 	srcObj, err := cloudprovider.GetIObject(srcBucket, args.SRCKEY)
   821  	// 	if err != nil {
   822  	// 		return err
   823  	// 	}
   824  	// 	meta := args.ObjectHeaderOptions.Options2Header()
   825  	// 	if args.Native {
   826  	// 		err = dstBucket.CopyObject(ctx, args.DSTKEY, args.SRC, args.SRCKEY, srcObj.GetAcl(), srcObj.GetStorageClass(), meta)
   827  	// 		if err != nil {
   828  	// 			return err
   829  	// 		}
   830  	// 	} else {
   831  	// 		err = cloudprovider.CopyObject(ctx, args.BlockSize*1000*1000, dstBucket, args.DSTKEY, srcBucket, args.SRCKEY, meta, args.Debug)
   832  	// 		if err != nil {
   833  	// 			return err
   834  	// 		}
   835  	// 	}
   836  	// 	fmt.Println("Success!")
   837  	// 	return nil
   838  	// })
   839  	//
   840  	// type ObjectMetaOptions struct {
   841  	// 	BUCKET string `help:"bucket name"`
   842  	// 	KEY    string `help:"object key"`
   843  	// }
   844  	// RegionR(&ObjectMetaOptions{}, "object-meta", "Show object meta header", func(cli cloudprovider.ICloudRegion, args *ObjectMetaOptions) error {
   845  	// 	bucket, err := cli.GetIBucketByName(args.BUCKET)
   846  	// 	if err != nil {
   847  	// 		return err
   848  	// 	}
   849  	// 	obj, err := cloudprovider.GetIObject(bucket, args.KEY)
   850  	// 	if err != nil {
   851  	// 		return err
   852  	// 	}
   853  	// 	meta := obj.GetMeta()
   854  	// 	for k, v := range meta {
   855  	// 		fmt.Println(k, ": ", v[0])
   856  	// 	}
   857  	// 	return nil
   858  	// })
   859  	//
   860  	// type ObjectSetMetaOptions struct {
   861  	// 	BUCKET string `help:"bucket name"`
   862  	// 	KEY    string `help:"object key"`
   863  	//
   864  	// 	ObjectHeaderOptions
   865  	// }
   866  	// RegionR(&ObjectSetMetaOptions{}, "object-set-meta", "Set object meta header", func(cli cloudprovider.ICloudRegion, args *ObjectSetMetaOptions) error {
   867  	// 	bucket, err := cli.GetIBucketByName(args.BUCKET)
   868  	// 	if err != nil {
   869  	// 		return err
   870  	// 	}
   871  	// 	obj, err := cloudprovider.GetIObject(bucket, args.KEY)
   872  	// 	if err != nil {
   873  	// 		return err
   874  	// 	}
   875  	// 	meta := args.ObjectHeaderOptions.Options2Header()
   876  	// 	err = obj.SetMeta(context.Background(), meta)
   877  	// 	if err != nil {
   878  	// 		return err
   879  	// 	}
   880  	// 	return nil
   881  	// })
   882  }