diff --git a/backend/app/service/cornjob.go b/backend/app/service/cornjob.go index ef336993a..7a6285b77 100644 --- a/backend/app/service/cornjob.go +++ b/backend/app/service/cornjob.go @@ -133,7 +133,7 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) { } if backup.Type == "LOCAL" || record.FromLocal { if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) { - return "", constant.ErrRecordNotFound + return "", err } return record.File, nil } @@ -145,7 +145,7 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) { _ = os.MkdirAll(path.Dir(tempPath), os.ModePerm) isOK, err := client.Download(record.File, tempPath) if !isOK || err != nil { - return "", constant.ErrRecordNotFound + return "", err } return tempPath, nil } diff --git a/backend/utils/cloud_storage/client/cos.go b/backend/utils/cloud_storage/client/cos.go index cd615ca5b..e10aa770c 100644 --- a/backend/utils/cloud_storage/client/cos.go +++ b/backend/utils/cloud_storage/client/cos.go @@ -14,6 +14,7 @@ type cosClient struct { region string accessKey string secretKey string + scType string Vars map[string]interface{} client *cosSDK.Client } @@ -21,6 +22,7 @@ type cosClient struct { func NewCosClient(vars map[string]interface{}) (*cosClient, error) { var accessKey string var secretKey string + var scType string var region string if _, ok := vars["region"]; ok { region = vars["region"].(string) @@ -32,6 +34,11 @@ func NewCosClient(vars map[string]interface{}) (*cosClient, error) { } else { return nil, constant.ErrInvalidParams } + if _, ok := vars["scType"]; ok { + scType = vars["scType"].(string) + } else { + scType = "Standard" + } if _, ok := vars["secretKey"]; ok { secretKey = vars["secretKey"].(string) } else { @@ -47,7 +54,7 @@ func NewCosClient(vars map[string]interface{}) (*cosClient, error) { }, }) - return &cosClient{Vars: vars, client: client, accessKey: accessKey, secretKey: secretKey, region: region}, nil + return &cosClient{Vars: vars, client: client, accessKey: accessKey, secretKey: secretKey, scType: scType, region: region}, nil } func (cos cosClient) ListBuckets() ([]interface{}, error) { @@ -90,7 +97,12 @@ func (cos cosClient) Upload(src, target string) (bool, error) { if err != nil { return false, err } - if _, err := client.Object.PutFromFile(context.Background(), target, src, &cosSDK.ObjectPutOptions{}); err != nil { + if _, err := client.Object.PutFromFile(context.Background(), target, src, &cosSDK.ObjectPutOptions{ + ACLHeaderOptions: nil, + ObjectPutHeaderOptions: &cosSDK.ObjectPutHeaderOptions{ + XCosStorageClass: cos.scType, + }, + }); err != nil { return false, err } return true, nil diff --git a/backend/utils/cloud_storage/client/oss.go b/backend/utils/cloud_storage/client/oss.go index 7c3337ddf..852fc400f 100644 --- a/backend/utils/cloud_storage/client/oss.go +++ b/backend/utils/cloud_storage/client/oss.go @@ -6,6 +6,7 @@ import ( ) type ossClient struct { + scType string Vars map[string]interface{} client osssdk.Client } @@ -14,6 +15,7 @@ func NewOssClient(vars map[string]interface{}) (*ossClient, error) { var endpoint string var accessKey string var secretKey string + var scType string if _, ok := vars["endpoint"]; ok { endpoint = vars["endpoint"].(string) } else { @@ -24,6 +26,11 @@ func NewOssClient(vars map[string]interface{}) (*ossClient, error) { } else { return nil, constant.ErrInvalidParams } + if _, ok := vars["scType"]; ok { + scType = vars["scType"].(string) + } else { + scType = "Standard" + } if _, ok := vars["secretKey"]; ok { secretKey = vars["secretKey"].(string) } else { @@ -34,6 +41,7 @@ func NewOssClient(vars map[string]interface{}) (*ossClient, error) { return nil, err } return &ossClient{ + scType: scType, Vars: vars, client: *client, }, nil @@ -77,7 +85,7 @@ func (oss ossClient) Upload(src, target string) (bool, error) { if err != nil { return false, err } - err = bucket.UploadFile(target, src, 200*1024*1024, osssdk.Routines(5), osssdk.Checkpoint(true, "")) + err = bucket.UploadFile(target, src, 200*1024*1024, osssdk.Routines(5), osssdk.Checkpoint(true, ""), osssdk.ObjectStorageClass(osssdk.StorageClassType(oss.scType))) if err != nil { return false, err } diff --git a/backend/utils/cloud_storage/client/s3.go b/backend/utils/cloud_storage/client/s3.go index f4970cc4f..ea1605d42 100644 --- a/backend/utils/cloud_storage/client/s3.go +++ b/backend/utils/cloud_storage/client/s3.go @@ -13,14 +13,16 @@ import ( ) type s3Client struct { - Vars map[string]interface{} - Sess session.Session + scType string + Vars map[string]interface{} + Sess session.Session } func NewS3Client(vars map[string]interface{}) (*s3Client, error) { var accessKey string var secretKey string var endpoint string + var scType string var region string if _, ok := vars["accessKey"]; ok { accessKey = vars["accessKey"].(string) @@ -32,6 +34,11 @@ func NewS3Client(vars map[string]interface{}) (*s3Client, error) { } else { return nil, constant.ErrInvalidParams } + if _, ok := vars["scType"]; ok { + scType = vars["scType"].(string) + } else { + scType = "Standard" + } if _, ok := vars["endpoint"]; ok { endpoint = vars["endpoint"].(string) } else { @@ -53,8 +60,9 @@ func NewS3Client(vars map[string]interface{}) (*s3Client, error) { return nil, err } return &s3Client{ - Vars: vars, - Sess: *sess, + scType: scType, + Vars: vars, + Sess: *sess, }, nil } @@ -126,9 +134,10 @@ func (s3C s3Client) Upload(src, target string) (bool, error) { uploader := s3manager.NewUploader(&s3C.Sess) _, err = uploader.Upload(&s3manager.UploadInput{ - Bucket: aws.String(bucket), - Key: aws.String(target), - Body: file, + Bucket: aws.String(bucket), + Key: aws.String(target), + Body: file, + StorageClass: &s3C.scType, }) if err != nil { return false, err diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 5a8274046..0980b29fa 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -997,6 +997,19 @@ const message = { loadCode: 'Acquire', COS: 'Tencent COS', KODO: 'Qiniu Kodo', + scType: ' Storage type', + typeStandard: 'Standard', + typeStandard_IA: 'Standard_IA', + typeArchive: 'Archive', + typeDeep_Archive: 'Deep_Archive', + scStandard: + 'Standard Storage is suitable for business scenarios with a large number of hot files that require real-time access, frequent data interaction, and so on.', + scStandard_IA: + 'Low-frequency storage is suitable for business scenarios with relatively low access frequency, and stores data for at least 30 days.', + scArchive: 'Archival storage is suitable for business scenarios with extremely low access frequency.', + scDeep_Archive: 'Durable cold storage is suitable for business scenarios with extremely low access frequency.', + archiveHelper: + 'Archival storage files cannot be downloaded directly and must first be restored through the corresponding cloud service provider`s website. Please use with caution!', domainHelper: 'The accelerated domain name must contain http:// or https://', backupAlert: "In theory, as long as the cloud provider is compatible with the S3 protocol, existing Amazon S3 cloud storage can be used for backup. For specific configurations, please refer to the official documentation. ", diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index a6539f88a..d3d96dca9 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -975,6 +975,16 @@ const message = { loadCode: '获取', COS: '腾讯云 COS', KODO: '七牛云 Kodo', + scType: '存储类型', + typeStandard: '标准存储', + typeStandard_IA: '低频存储', + typeArchive: '归档存储', + typeDeep_Archive: '深度归档存储', + scStandard: '标准存储,适用于实时访问的大量热点文件、频繁的数据交互等业务场景。', + scStandard_IA: '低频存储,适用于较低访问频率(例如平均每月访问频率1到2次)的业务场景,最少存储30天。', + scArchive: '归档存储,适用于极低访问频率(例如半年访问1次)的业务场景。', + scDeep_Archive: '深度归档存储,适用于极低访问频率(例如1年访问1~2次)的业务场景。', + archiveHelper: '归档存储的文件无法直接下载,需要先在对应的云服务商网站进行恢复操作,请谨慎使用!', domainHelper: '加速域名必须包含 http:// 或者 https://', backupAlert: "理论上只要云厂商兼容 S3 协议,就可以用现有的亚马逊 S3 云存储来备份,具体配置参考 官方文档 ", diff --git a/frontend/src/views/setting/backup-account/index.vue b/frontend/src/views/setting/backup-account/index.vue index 296db77f3..cfaa7f079 100644 --- a/frontend/src/views/setting/backup-account/index.vue +++ b/frontend/src/views/setting/backup-account/index.vue @@ -66,6 +66,20 @@ {{ s3Data.bucket }} + + + {{ $t('setting.typeStandard') }} + + + {{ $t('setting.typeStandard_IA') }} + + + {{ $t('setting.typeArchive') }} + + + {{ $t('setting.typeDeep_Archive') }} + + {{ s3Data.backupPath }} @@ -73,7 +87,7 @@ {{ dateFormat(0, 0, s3Data.createdAt) }} - + {{ $t('setting.createBackupAccount', [$t('setting.S3')]) }} @@ -105,6 +119,20 @@ {{ ossData.bucket }} + + + {{ $t('setting.typeStandard') }} + + + {{ $t('setting.typeStandard_IA') }} + + + {{ $t('setting.typeArchive') }} + + + {{ $t('setting.typeDeep_Archive') }} + + {{ ossData.backupPath }} @@ -112,7 +140,7 @@ {{ dateFormat(0, 0, ossData.createdAt) }} - + {{ $t('setting.createBackupAccount', [$t('setting.OSS')]) }} @@ -145,6 +173,20 @@ {{ cosData.bucket }} + + + {{ $t('setting.typeStandard') }} + + + {{ $t('setting.typeStandard_IA') }} + + + {{ $t('setting.typeArchive') }} + + + {{ $t('setting.typeDeep_Archive') }} + + {{ cosData.backupPath }} @@ -152,7 +194,7 @@ {{ dateFormat(0, 0, cosData.createdAt) }} - + {{ $t('setting.createBackupAccount', [$t('setting.COS')]) }} @@ -185,7 +227,7 @@ {{ dateFormat(0, 0, oneDriveData.createdAt) }} - + - + {{ $t('setting.createBackupAccount', [$t('setting.KODO')]) }} @@ -270,7 +312,7 @@ {{ dateFormat(0, 0, minioData.createdAt) }} - + {{ $t('setting.createBackupAccount', [$t('setting.MINIO')]) }} @@ -314,7 +356,7 @@ {{ dateFormat(0, 0, sftpData.createdAt) }} - + {{ $t('setting.createBackupAccount', [$t('setting.SFTP')]) }} @@ -361,6 +403,7 @@ const ossData = ref({ varsJson: { region: '', endpoint: '', + scType: 'Standard', }, createdAt: new Date(), }); @@ -415,6 +458,7 @@ const s3Data = ref({ vars: '', varsJson: { region: '', + scType: 'Standard', endpoint: '', }, createdAt: new Date(), @@ -429,6 +473,7 @@ const cosData = ref({ vars: '', varsJson: { region: '', + scType: 'Standard', }, createdAt: new Date(), }); diff --git a/frontend/src/views/setting/backup-account/operate/index.vue b/frontend/src/views/setting/backup-account/operate/index.vue index 95325c490..cbe2bb872 100644 --- a/frontend/src/views/setting/backup-account/operate/index.vue +++ b/frontend/src/views/setting/backup-account/operate/index.vue @@ -117,6 +117,66 @@ {{ $t('commons.rule.requiredSelect') }} + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -156,14 +216,14 @@ :label="$t('setting.backupDir')" prop="backupPath" > - +