Skip to content

Commit ec01411

Browse files
committed
[feature] add alibaba cloud oss support
1 parent cc4e328 commit ec01411

File tree

10 files changed

+199
-13
lines changed

10 files changed

+199
-13
lines changed

manager/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<easy-poi.version>4.3.0</easy-poi.version>
3838
<huawei.sdk.version>3.1.37</huawei.sdk.version>
3939
<huawei.obs.version>3.23.5</huawei.obs.version>
40+
<alibaba.oss.version>3.17.4</alibaba.oss.version>
4041
</properties>
4142

4243
<dependencies>
@@ -198,6 +199,11 @@
198199
</exclusion>
199200
</exclusions>
200201
</dependency>
202+
<dependency>
203+
<groupId>com.aliyun.oss</groupId>
204+
<artifactId>aliyun-sdk-oss</artifactId>
205+
<version>${alibaba.oss.version}</version>
206+
</dependency>
201207
</dependencies>
202208

203209
<build>

manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/ObjectStoreDTO.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ public enum Type {
5454
/**
5555
* <a href="https://support.huaweicloud.com/obs/index.html">Huawei Cloud OBS</a>
5656
*/
57-
OBS
57+
OBS,
58+
59+
/**
60+
* <a href="https://oss.console.aliyun.com/services/tools">Alibaba Cloud OSS</a>
61+
*/
62+
OSS,
5863
}
5964

6065
/**
@@ -73,4 +78,20 @@ public static class ObsConfig {
7378
private String savePath = "hertzbeat";
7479
}
7580

81+
/**
82+
* file oss storage configuration
83+
*/
84+
@Data
85+
public static class OssConfig {
86+
private String accessKey;
87+
private String secretKey;
88+
private String bucketName;
89+
private String endpoint;
90+
91+
/**
92+
* Save path
93+
*/
94+
private String savePath = "hertzbeat";
95+
}
96+
7697
}

manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.hertzbeat.manager.service.impl;
1919

20+
import com.aliyun.oss.OSSClientBuilder;
2021
import com.fasterxml.jackson.core.type.TypeReference;
2122
import com.fasterxml.jackson.databind.ObjectMapper;
2223
import com.obs.services.ObsClient;
@@ -83,10 +84,28 @@ public void handler(ObjectStoreDTO<T> config) {
8384
initObs(config);
8485
// case other object store service
8586
}
87+
if (config.getType() == ObjectStoreDTO.Type.OSS) {
88+
initOss(config);
89+
}
8690
ctx.publishEvent(new ObjectStoreConfigChangeEvent(config));
8791
}
8892
}
8993

94+
private void initOss(ObjectStoreDTO<T> config) {
95+
var ossConfig = objectMapper.convertValue(config.getConfig(), ObjectStoreDTO.OssConfig.class);
96+
Assert.hasText(ossConfig.getAccessKey(), "cannot find oss accessKey");
97+
Assert.hasText(ossConfig.getSecretKey(), "cannot find oss secretKey");
98+
Assert.hasText(ossConfig.getEndpoint(), "cannot find oss endpoint");
99+
Assert.hasText(ossConfig.getBucketName(), "cannot find oss bucket name");
100+
101+
var ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKey(), ossConfig.getSecretKey());
102+
103+
beanFactory.destroySingleton(BEAN_NAME);
104+
beanFactory.registerSingleton(BEAN_NAME, new OssObjectStoreServiceImpl(ossClient, ossConfig.getBucketName(), ossConfig.getSavePath()));
105+
106+
log.info("oss store service init success.");
107+
}
108+
90109
/**
91110
* init Huawei Cloud OBS
92111
*/
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hertzbeat.manager.service.impl;
19+
20+
import com.aliyun.oss.OSS;
21+
import com.aliyun.oss.model.ListObjectsRequest;
22+
import com.aliyun.oss.model.OSSObjectSummary;
23+
import java.io.InputStream;
24+
import java.util.List;
25+
import java.util.Objects;
26+
import lombok.extern.slf4j.Slf4j;
27+
import org.apache.hertzbeat.common.constants.SignConstants;
28+
import org.apache.hertzbeat.manager.pojo.dto.FileDTO;
29+
import org.apache.hertzbeat.manager.pojo.dto.ObjectStoreDTO;
30+
import org.apache.hertzbeat.manager.service.ObjectStoreService;
31+
32+
/**
33+
* Alibaba cloud storage service
34+
*/
35+
@Slf4j
36+
public class OssObjectStoreServiceImpl implements ObjectStoreService {
37+
38+
private final OSS ossClient;
39+
40+
private final String bucketName;
41+
private final String rootPath;
42+
43+
public OssObjectStoreServiceImpl(OSS ossClient, String bucketName, String rootPath) {
44+
this.ossClient = ossClient;
45+
this.bucketName = bucketName;
46+
if (rootPath.startsWith(SignConstants.RIGHT_DASH)) {
47+
this.rootPath = rootPath.substring(1);
48+
} else {
49+
this.rootPath = rootPath;
50+
}
51+
}
52+
53+
@Override
54+
public boolean upload(String filePath, InputStream is) {
55+
var objectKey = getObjectKey(filePath);
56+
var response = ossClient.putObject(bucketName, objectKey, is);
57+
return Objects.equals(response.getResponse().getStatusCode(), 200);
58+
}
59+
60+
@Override
61+
public FileDTO download(String filePath) {
62+
var objectKey = getObjectKey(filePath);
63+
try {
64+
var ossObject = ossClient.getObject(bucketName, objectKey);
65+
return new FileDTO(filePath, ossObject.getObjectContent());
66+
} catch (Exception ex) {
67+
log.warn("download file from oss error {}", objectKey);
68+
return null;
69+
}
70+
}
71+
72+
@Override
73+
public List<FileDTO> list(String dir) {
74+
var request = new ListObjectsRequest(bucketName);
75+
request.setPrefix(getObjectKey(dir));
76+
return ossClient.listObjects(request).getObjectSummaries().stream()
77+
.map(OSSObjectSummary::getKey).toList().stream()
78+
.map(k -> new FileDTO(k, ossClient.getObject(bucketName, k).getObjectContent())).toList();
79+
}
80+
81+
@Override
82+
public ObjectStoreDTO.Type type() {
83+
return ObjectStoreDTO.Type.OSS;
84+
}
85+
86+
87+
private String getObjectKey(String filePath) {
88+
return rootPath + SignConstants.RIGHT_DASH + filePath;
89+
}
90+
}

web-app/src/app/pojo/ObjectStore.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ export enum ObjectStoreType {
3232
/**
3333
* <a href="https://support.huaweicloud.com/obs/index.html">华为云OBS</a>
3434
*/
35-
OBS = 'OBS'
35+
OBS = 'OBS',
36+
/**
37+
* <a href="https://oss.console.aliyun.com/services/tools">Alibaba Cloud OSS</a>
38+
*/
39+
OSS = 'OSS',
3640
}
3741

3842
export class ObsConfig {
@@ -42,3 +46,12 @@ export class ObsConfig {
4246
endpoint!: string;
4347
savePath: string = 'hertzbeat';
4448
}
49+
50+
export class OssConfig {
51+
accessKey!: string;
52+
secretKey!: string;
53+
bucketName!: string;
54+
endpoint!: string;
55+
savePath: string = 'hertzbeat';
56+
}
57+

web-app/src/app/routes/setting/settings/object-store/object-store.component.html

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,17 @@
3232
>
3333
<nz-option [nzValue]="ObjectStoreType.FILE" [nzLabel]="'settings.object-store.type.file' | i18n"></nz-option>
3434
<nz-option [nzValue]="ObjectStoreType.OBS" [nzLabel]="'settings.object-store.type.obs' | i18n"></nz-option>
35+
<nz-option [nzValue]="ObjectStoreType.OSS" [nzLabel]="'settings.object-store.type.oss' | i18n"></nz-option>
3536
</nz-select>
3637
</nz-form-item>
37-
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
38+
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS || config.type == ObjectStoreType.OSS">
3839
<nz-form-label [nzSpan]="6" nzFor="obs.accessKey" nzRequired="true">{{
3940
'settings.object-store.obs.accessKey' | i18n
4041
}}</nz-form-label>
4142
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
4243
<input
4344
[(ngModel)]="config.config.accessKey"
44-
placeholder="{{ 'settings.object-store.obs.accessKey.placeholder' | i18n }}"
45+
placeholder="{{ config.type == ObjectStoreType.OBS?'settings.object-store.obs.bucketName.placeholder':'settings.object-store.oss.bucketName.placeholder' | i18n }}"
4546
nz-input
4647
required
4748
name="accessKey"
@@ -50,14 +51,14 @@
5051
/>
5152
</nz-form-control>
5253
</nz-form-item>
53-
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
54+
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS || config.type == ObjectStoreType.OSS">
5455
<nz-form-label [nzSpan]="6" nzFor="obs.secretKey" nzRequired="true">{{
5556
'settings.object-store.obs.secretKey' | i18n
5657
}}</nz-form-label>
5758
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
5859
<input
5960
[(ngModel)]="config.config.secretKey"
60-
placeholder="{{ 'settings.object-store.obs.secretKey.placeholder' | i18n }}"
61+
placeholder="{{config.type == ObjectStoreType.OBS?'settings.object-store.obs.bucketName.placeholder':'settings.object-store.oss.bucketName.placeholder' | i18n }}"
6162
nz-input
6263
required
6364
name="secretKey"
@@ -66,14 +67,14 @@
6667
/>
6768
</nz-form-control>
6869
</nz-form-item>
69-
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
70+
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS || config.type == ObjectStoreType.OSS">
7071
<nz-form-label [nzSpan]="6" nzFor="obs.bucketName" nzRequired="true">{{
7172
'settings.object-store.obs.bucketName' | i18n
7273
}}</nz-form-label>
7374
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
7475
<input
7576
[(ngModel)]="config.config.bucketName"
76-
placeholder="{{ 'settings.object-store.obs.bucketName.placeholder' | i18n }}"
77+
placeholder="{{config.type == ObjectStoreType.OBS?'settings.object-store.obs.bucketName.placeholder':'settings.object-store.oss.bucketName.placeholder' | i18n }}"
7778
nz-input
7879
required
7980
name="bucketName"
@@ -82,14 +83,14 @@
8283
/>
8384
</nz-form-control>
8485
</nz-form-item>
85-
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
86+
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS || config.type == ObjectStoreType.OSS">
8687
<nz-form-label [nzSpan]="6" nzFor="obs.endpoint" nzRequired="true">{{
8788
'settings.object-store.obs.endpoint' | i18n
8889
}}</nz-form-label>
8990
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
9091
<input
9192
[(ngModel)]="config.config.endpoint"
92-
placeholder="{{ 'settings.object-store.obs.endpoint.placeholder' | i18n }}"
93+
placeholder="{{ config.type == ObjectStoreType.OBS?'settings.object-store.obs.bucketName.placeholder':'settings.object-store.oss.bucketName.placeholder' | i18n }}"
9394
nz-input
9495
required
9596
name="endpoint"
@@ -98,14 +99,14 @@
9899
/>
99100
</nz-form-control>
100101
</nz-form-item>
101-
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS">
102+
<nz-form-item *ngIf="config.type == ObjectStoreType.OBS || config.type == ObjectStoreType.OSS">
102103
<nz-form-label [nzSpan]="6" nzFor="obs.savePath" nzRequired="true">{{
103104
'settings.object-store.obs.savePath' | i18n
104105
}}</nz-form-label>
105106
<nz-form-control [nzErrorTip]="'validation.required' | i18n">
106107
<input
107108
[(ngModel)]="config.config.savePath"
108-
placeholder="{{ 'settings.object-store.obs.savePath.placeholder' | i18n }}"
109+
placeholder="{{ config.type == ObjectStoreType.OBS?'settings.object-store.obs.bucketName.placeholder':'settings.object-store.oss.bucketName.placeholder' | i18n }}"
109110
nz-input
110111
required
111112
name="savePath"

web-app/src/app/routes/setting/settings/object-store/object-store.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
2222
import { NzNotificationService } from 'ng-zorro-antd/notification';
2323
import { finalize } from 'rxjs/operators';
2424

25-
import { ObjectStore, ObjectStoreType, ObsConfig } from '../../../../pojo/ObjectStore';
25+
import {ObjectStore, ObjectStoreType, ObsConfig, OssConfig} from '../../../../pojo/ObjectStore';
2626
import { GeneralConfigService } from '../../../../service/general-config.service';
2727

2828
const key = 'oss';
@@ -112,6 +112,9 @@ export class ObjectStoreComponent implements OnInit {
112112
case ObjectStoreType.OBS:
113113
this.config.config = new ObsConfig();
114114
break;
115+
case ObjectStoreType.OSS:
116+
this.config.config = new OssConfig();
117+
break;
115118
}
116119
};
117120

web-app/src/assets/i18n/en-US.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@
551551
"settings.object-store.type": "File Server Provider",
552552
"settings.object-store.type.file": "Local file (default)",
553553
"settings.object-store.type.obs": "HUAWEI CLOUD OBS",
554+
"settings.object-store.type.oss": "ALIBABA CLOUD OSS",
554555
"settings.object-store.obs.accessKey": "AccessKey",
555556
"settings.object-store.obs.accessKey.placeholder": "Access Key ID of HUAWEI CLOUD",
556557
"settings.object-store.obs.secretKey": "SecretKey",
@@ -561,6 +562,16 @@
561562
"settings.object-store.obs.endpoint.placeholder": "HUAWEI CLOUD OBS domain name, excluding the bucket name",
562563
"settings.object-store.obs.savePath": "SavePath",
563564
"settings.object-store.obs.savePath.placeholder": "Path to save the backup file, The default value is hertzbeat.",
565+
"settings.object-store.oss.accessKey": "AccessKey",
566+
"settings.object-store.oss.accessKey.placeholder": "Access Key ID of ALIBABA CLOUD",
567+
"settings.object-store.oss.secretKey": "SecretKey",
568+
"settings.object-store.oss.secretKey.placeholder": "Access Key Secret of ALIBABA CLOUD",
569+
"settings.object-store.oss.bucketName": "Bucket",
570+
"settings.object-store.oss.bucketName.placeholder": "The name of the bucket you created in ALIBABA CLOUD OSS",
571+
"settings.object-store.oss.endpoint": "EndPoint",
572+
"settings.object-store.oss.endpoint.placeholder": "ALIBABA CLOUD OSS domain name, excluding the bucket name",
573+
"settings.object-store.oss.savePath": "SavePath",
574+
"settings.object-store.oss.savePath.placeholder": "Path to save the backup file, The default value is hertzbeat.",
564575
"collector": "Collector",
565576
"collector.name": "Collector Name",
566577
"collector.name.placeholder": "Please config the unique name of the collector",

web-app/src/assets/i18n/zh-CN.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@
552552
"settings.object-store.type": "文件服务提供商",
553553
"settings.object-store.type.file": "本地文件(默认)",
554554
"settings.object-store.type.obs": "华为云OBS",
555+
"settings.object-store.type.oss": "阿里云OSS",
555556
"settings.object-store.obs.accessKey": "AccessKey",
556557
"settings.object-store.obs.accessKey.placeholder": "华为云的AccessKeyId",
557558
"settings.object-store.obs.secretKey": "SecretKey",
@@ -562,6 +563,16 @@
562563
"settings.object-store.obs.endpoint.placeholder": "华为云OBS地域域名,不包括Bucket名",
563564
"settings.object-store.obs.savePath": "保存路径",
564565
"settings.object-store.obs.savePath.placeholder": "备份文件保存路径, 默认是hertzbeat",
566+
"settings.object-store.oss.accessKey": "AccessKey",
567+
"settings.object-store.oss.accessKey.placeholder": "阿里云的AccessKeyId",
568+
"settings.object-store.oss.secretKey": "SecretKey",
569+
"settings.object-store.oss.secretKey.placeholder": "阿里云的AccessKeySecret",
570+
"settings.object-store.oss.bucketName": "Bucket",
571+
"settings.object-store.oss.bucketName.placeholder": "阿里云OSS中您创建的Bucket名称",
572+
"settings.object-store.oss.endpoint": "EndPoint",
573+
"settings.object-store.oss.endpoint.placeholder": "阿里云OSS地域域名,不包括Bucket名",
574+
"settings.object-store.oss.savePath": "保存路径",
575+
"settings.object-store.oss.savePath.placeholder": "备份文件保存路径, 默认是hertzbeat",
565576
"collector": "采集器",
566577
"collector.name": "采集器名称",
567578
"collector.name.placeholder": "请配置待部署的采集器名称,注意需保证唯一性",

web-app/src/assets/i18n/zh-TW.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@
549549
"settings.object-store.type": "文件服務提供商",
550550
"settings.object-store.type.file": "本地文件(默認)",
551551
"settings.object-store.type.obs": "華為雲OBS",
552+
"settings.object-store.type.oss": "阿裏雲OSS",
552553
"settings.object-store.obs.accessKey": "AccessKey",
553554
"settings.object-store.obs.accessKey.placeholder": "華為雲的AccessKeyId",
554555
"settings.object-store.obs.secretKey": "SecretKey",
@@ -559,6 +560,16 @@
559560
"settings.object-store.obs.endpoint.placeholder": "華為雲OBS地域域名,不包括Bucket名",
560561
"settings.object-store.obs.savePath": "保存路徑",
561562
"settings.object-store.obs.savePath.placeholder": "備份文件保存路徑, 默認是hertzbeat",
563+
"settings.object-store.oss.accessKey": "AccessKey",
564+
"settings.object-store.oss.accessKey.placeholder": "阿裏雲的AccessKeyId",
565+
"settings.object-store.oss.secretKey": "SecretKey",
566+
"settings.object-store.oss.secretKey.placeholder": "阿裏雲的AccessKeySecret",
567+
"settings.object-store.oss.bucketName": "Bucket",
568+
"settings.object-store.oss.bucketName.placeholder": "阿裏雲OSS中您創建的Bucket名稱",
569+
"settings.object-store.oss.endpoint": "EndPoint",
570+
"settings.object-store.oss.endpoint.placeholder": "阿裏雲OSS地域域名,不包括Bucket名",
571+
"settings.object-store.oss.savePath": "保存路徑",
572+
"settings.object-store.oss.savePath.placeholder": "備份文件保存路徑, 默認是hertzbeat",
562573
"collector": "採集器",
563574
"collector.name": "採集器名称",
564575
"collector.name.placeholder": "請配置待部署的採集器名稱,注意需保證唯一性",

0 commit comments

Comments
 (0)