2021-07-21 09:24:34 +00:00
package shell
import (
"context"
"flag"
"fmt"
"github.com/chrislusf/seaweedfs/weed/filer"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
2021-08-26 22:18:34 +00:00
"github.com/chrislusf/seaweedfs/weed/pb/remote_pb"
2021-07-21 09:24:34 +00:00
"github.com/chrislusf/seaweedfs/weed/util"
2021-08-08 08:21:42 +00:00
"github.com/golang/protobuf/jsonpb"
2021-07-21 09:24:34 +00:00
"github.com/golang/protobuf/proto"
"io"
"regexp"
2021-07-27 08:16:28 +00:00
"strings"
2021-07-21 09:24:34 +00:00
)
func init ( ) {
Commands = append ( Commands , & commandRemoteConfigure { } )
}
type commandRemoteConfigure struct {
}
func ( c * commandRemoteConfigure ) Name ( ) string {
return "remote.configure"
}
func ( c * commandRemoteConfigure ) Help ( ) string {
return ` remote storage configuration
# see the current configurations
remote . configure
# set or update a configuration
2021-08-23 07:37:55 +00:00
remote . configure - name = cloud1 - type = s3 - s3 . access_key = xxx - s3 . secret_key = yyy
remote . configure - name = cloud2 - type = gcs - gcs . appCredentialsFile = ~ / service - account - file . json
2021-08-24 08:18:30 +00:00
remote . configure - name = cloud3 - type = azure - azure . account_name = xxx - azure . account_key = yyy
2021-07-21 09:24:34 +00:00
# delete one configuration
remote . configure - delete - name = cloud1
`
}
var (
isAlpha = regexp . MustCompile ( ` ^[A-Za-z][A-Za-z0-9]*$ ` ) . MatchString
)
func ( c * commandRemoteConfigure ) Do ( args [ ] string , commandEnv * CommandEnv , writer io . Writer ) ( err error ) {
2021-08-26 22:18:34 +00:00
conf := & remote_pb . RemoteConf { }
2021-07-21 09:24:34 +00:00
remoteConfigureCommand := flag . NewFlagSet ( c . Name ( ) , flag . ContinueOnError )
isDelete := remoteConfigureCommand . Bool ( "delete" , false , "delete one remote storage by its name" )
remoteConfigureCommand . StringVar ( & conf . Name , "name" , "" , "a short name to identify the remote storage" )
2021-08-26 00:34:29 +00:00
remoteConfigureCommand . StringVar ( & conf . Type , "type" , "s3" , "[s3|gcs|azure|b2|aliyun|tencent|baidu|wasabi] storage type" )
2021-07-21 09:24:34 +00:00
remoteConfigureCommand . StringVar ( & conf . S3AccessKey , "s3.access_key" , "" , "s3 access key" )
remoteConfigureCommand . StringVar ( & conf . S3SecretKey , "s3.secret_key" , "" , "s3 secret key" )
remoteConfigureCommand . StringVar ( & conf . S3Region , "s3.region" , "us-east-2" , "s3 region" )
remoteConfigureCommand . StringVar ( & conf . S3Endpoint , "s3.endpoint" , "" , "endpoint for s3-compatible local object store" )
2021-08-23 09:18:56 +00:00
remoteConfigureCommand . StringVar ( & conf . S3StorageClass , "s3.storage_class" , "" , "s3 storage class" )
2021-08-23 10:30:41 +00:00
remoteConfigureCommand . BoolVar ( & conf . S3ForcePathStyle , "s3.force_path_style" , true , "s3 force path style" )
2021-07-21 09:24:34 +00:00
2021-08-24 08:18:30 +00:00
remoteConfigureCommand . StringVar ( & conf . GcsGoogleApplicationCredentials , "gcs.appCredentialsFile" , "" , "google cloud storage credentials file, default to use env GOOGLE_APPLICATION_CREDENTIALS" )
remoteConfigureCommand . StringVar ( & conf . AzureAccountName , "azure.account_name" , "" , "azure account name, default to use env AZURE_STORAGE_ACCOUNT" )
remoteConfigureCommand . StringVar ( & conf . AzureAccountKey , "azure.account_key" , "" , "azure account name, default to use env AZURE_STORAGE_ACCESS_KEY" )
2021-08-23 07:29:27 +00:00
2021-08-25 05:30:06 +00:00
remoteConfigureCommand . StringVar ( & conf . BackblazeKeyId , "b2.key_id" , "" , "backblaze keyID" )
remoteConfigureCommand . StringVar ( & conf . BackblazeApplicationKey , "b2.application_key" , "" , "backblaze applicationKey. Note that your Master Application Key will not work with the S3 Compatible API. You must create a new key that is eligible for use. For more information: https://help.backblaze.com/hc/en-us/articles/360047425453" )
remoteConfigureCommand . StringVar ( & conf . BackblazeEndpoint , "b2.endpoint" , "" , "backblaze endpoint" )
2021-08-25 06:25:36 +00:00
remoteConfigureCommand . StringVar ( & conf . AliyunAccessKey , "aliyun.access_key" , "" , "Aliyun access key, default to use env ALICLOUD_ACCESS_KEY_ID" )
remoteConfigureCommand . StringVar ( & conf . AliyunSecretKey , "aliyun.secret_key" , "" , "Aliyun secret key, default to use env ALICLOUD_ACCESS_KEY_SECRET" )
2021-08-25 06:14:24 +00:00
remoteConfigureCommand . StringVar ( & conf . AliyunEndpoint , "aliyun.endpoint" , "" , "Aliyun endpoint" )
2021-08-25 06:46:33 +00:00
remoteConfigureCommand . StringVar ( & conf . AliyunRegion , "aliyun.region" , "" , "Aliyun region" )
2021-08-25 06:14:24 +00:00
2021-08-25 06:25:36 +00:00
remoteConfigureCommand . StringVar ( & conf . TencentSecretId , "tencent.secret_id" , "" , "Tencent Secret Id, default to use env COS_SECRETID" )
remoteConfigureCommand . StringVar ( & conf . TencentSecretKey , "tencent.secret_key" , "" , "Tencent secret key, default to use env COS_SECRETKEY" )
2021-08-25 06:19:45 +00:00
remoteConfigureCommand . StringVar ( & conf . TencentEndpoint , "tencent.endpoint" , "" , "Tencent endpoint" )
2021-08-26 00:34:29 +00:00
remoteConfigureCommand . StringVar ( & conf . TencentRegion , "tencent.region" , "" , "Tencent region" )
2021-08-25 06:19:45 +00:00
2021-08-25 06:46:33 +00:00
remoteConfigureCommand . StringVar ( & conf . BaiduAccessKey , "baidu.access_key" , "" , "Baidu access key, default to use env BDCLOUD_ACCESS_KEY" )
remoteConfigureCommand . StringVar ( & conf . BaiduSecretKey , "baidu.secret_key" , "" , "Baidu secret key, default to use env BDCLOUD_SECRET_KEY" )
remoteConfigureCommand . StringVar ( & conf . BaiduEndpoint , "baidu.endpoint" , "" , "Baidu endpoint" )
remoteConfigureCommand . StringVar ( & conf . BaiduRegion , "baidu.region" , "" , "Baidu region" )
2021-08-26 00:34:29 +00:00
remoteConfigureCommand . StringVar ( & conf . WasabiAccessKey , "wasabi.access_key" , "" , "Wasabi access key" )
remoteConfigureCommand . StringVar ( & conf . WasabiSecretKey , "wasabi.secret_key" , "" , "Wasabi secret key" )
remoteConfigureCommand . StringVar ( & conf . WasabiEndpoint , "wasabi.endpoint" , "" , "Wasabi endpoint, see https://wasabi.com/wp-content/themes/wasabi/docs/API_Guide/index.html#t=topics%2Fapidiff-intro.htm" )
remoteConfigureCommand . StringVar ( & conf . WasabiRegion , "wasabi.region" , "" , "Wasabi region" )
2021-07-21 09:24:34 +00:00
if err = remoteConfigureCommand . Parse ( args ) ; err != nil {
return nil
}
if conf . Name == "" {
return c . listExistingRemoteStorages ( commandEnv , writer )
}
if ! isAlpha ( conf . Name ) {
return fmt . Errorf ( "only letters and numbers allowed in name: %v" , conf . Name )
}
if * isDelete {
return c . deleteRemoteStorage ( commandEnv , writer , conf . Name )
}
return c . saveRemoteStorage ( commandEnv , writer , conf )
}
func ( c * commandRemoteConfigure ) listExistingRemoteStorages ( commandEnv * CommandEnv , writer io . Writer ) error {
return filer_pb . ReadDirAllEntries ( commandEnv , util . FullPath ( filer . DirectoryEtcRemote ) , "" , func ( entry * filer_pb . Entry , isLast bool ) error {
if len ( entry . Content ) == 0 {
fmt . Fprintf ( writer , "skipping %s\n" , entry . Name )
return nil
}
2021-07-27 08:16:28 +00:00
if ! strings . HasSuffix ( entry . Name , filer . REMOTE_STORAGE_CONF_SUFFIX ) {
return nil
}
2021-08-26 22:18:34 +00:00
conf := & remote_pb . RemoteConf { }
2021-07-21 09:24:34 +00:00
if err := proto . Unmarshal ( entry . Content , conf ) ; err != nil {
return fmt . Errorf ( "unmarshal %s/%s: %v" , filer . DirectoryEtcRemote , entry . Name , err )
}
2021-08-17 18:27:08 +00:00
conf . S3SecretKey = strings . Repeat ( "*" , len ( conf . S3SecretKey ) )
2021-07-21 09:24:34 +00:00
2021-08-08 08:21:42 +00:00
m := jsonpb . Marshaler {
EmitDefaults : false ,
Indent : " " ,
}
2021-07-21 09:24:34 +00:00
2021-08-08 08:21:42 +00:00
err := m . Marshal ( writer , conf )
fmt . Fprintln ( writer )
return err
2021-07-21 09:24:34 +00:00
} )
}
func ( c * commandRemoteConfigure ) deleteRemoteStorage ( commandEnv * CommandEnv , writer io . Writer , storageName string ) error {
return commandEnv . WithFilerClient ( func ( client filer_pb . SeaweedFilerClient ) error {
request := & filer_pb . DeleteEntryRequest {
Directory : filer . DirectoryEtcRemote ,
2021-07-27 08:16:28 +00:00
Name : storageName + filer . REMOTE_STORAGE_CONF_SUFFIX ,
2021-07-21 09:24:34 +00:00
IgnoreRecursiveError : false ,
IsDeleteData : true ,
IsRecursive : true ,
IsFromOtherCluster : false ,
Signatures : nil ,
}
_ , err := client . DeleteEntry ( context . Background ( ) , request )
if err == nil {
fmt . Fprintf ( writer , "removed: %s\n" , storageName )
}
return err
} )
}
2021-08-26 22:18:34 +00:00
func ( c * commandRemoteConfigure ) saveRemoteStorage ( commandEnv * CommandEnv , writer io . Writer , conf * remote_pb . RemoteConf ) error {
2021-07-21 09:24:34 +00:00
data , err := proto . Marshal ( conf )
if err != nil {
return err
}
if err = commandEnv . WithFilerClient ( func ( client filer_pb . SeaweedFilerClient ) error {
2021-07-27 08:16:28 +00:00
return filer . SaveInsideFiler ( client , filer . DirectoryEtcRemote , conf . Name + filer . REMOTE_STORAGE_CONF_SUFFIX , data )
2021-07-21 09:24:34 +00:00
} ) ; err != nil && err != filer_pb . ErrNotFound {
return err
}
return nil
}