diff --git a/manager/pom.xml b/manager/pom.xml index 50b31d82fb3..dd53419f1e1 100644 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -37,6 +37,7 @@ 4.3.0 3.1.37 3.23.5 + 3.17.4 @@ -198,6 +199,11 @@ + + com.aliyun.oss + aliyun-sdk-oss + ${alibaba.oss.version} + diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/ObjectStoreDTO.java b/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/ObjectStoreDTO.java index 0a8a6fdb00b..07aca4ed2c6 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/ObjectStoreDTO.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/ObjectStoreDTO.java @@ -54,7 +54,12 @@ public enum Type { /** * Huawei Cloud OBS */ - OBS + OBS, + + /** + * Alibaba Cloud OSS + */ + OSS, } /** @@ -73,4 +78,20 @@ public static class ObsConfig { private String savePath = "hertzbeat"; } + /** + * file oss storage configuration + */ + @Data + public static class OssConfig { + private String accessKey; + private String secretKey; + private String bucketName; + private String endpoint; + + /** + * Save path + */ + private String savePath = "hertzbeat"; + } + } diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java index ed7dbef1d59..7425f863599 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/ObjectStoreConfigServiceImpl.java @@ -17,6 +17,7 @@ package org.apache.hertzbeat.manager.service.impl; +import com.aliyun.oss.OSSClientBuilder; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.obs.services.ObsClient; @@ -83,10 +84,28 @@ public void handler(ObjectStoreDTO config) { initObs(config); // case other object store service } + if (config.getType() == ObjectStoreDTO.Type.OSS) { + initOss(config); + } ctx.publishEvent(new ObjectStoreConfigChangeEvent(config)); } } + private void initOss(ObjectStoreDTO config) { + var ossConfig = objectMapper.convertValue(config.getConfig(), ObjectStoreDTO.OssConfig.class); + Assert.hasText(ossConfig.getAccessKey(), "cannot find oss accessKey"); + Assert.hasText(ossConfig.getSecretKey(), "cannot find oss secretKey"); + Assert.hasText(ossConfig.getEndpoint(), "cannot find oss endpoint"); + Assert.hasText(ossConfig.getBucketName(), "cannot find oss bucket name"); + + var ossClient = new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKey(), ossConfig.getSecretKey()); + + beanFactory.destroySingleton(BEAN_NAME); + beanFactory.registerSingleton(BEAN_NAME, new OssObjectStoreServiceImpl(ossClient, ossConfig.getBucketName(), ossConfig.getSavePath())); + + log.info("oss store service init success."); + } + /** * init Huawei Cloud OBS */ diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/OssObjectStoreServiceImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/OssObjectStoreServiceImpl.java new file mode 100644 index 00000000000..3f6ec362178 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/OssObjectStoreServiceImpl.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hertzbeat.manager.service.impl; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.model.ListObjectsRequest; +import com.aliyun.oss.model.OSSObjectSummary; +import java.io.InputStream; +import java.util.List; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import org.apache.hertzbeat.common.constants.SignConstants; +import org.apache.hertzbeat.manager.pojo.dto.FileDTO; +import org.apache.hertzbeat.manager.pojo.dto.ObjectStoreDTO; +import org.apache.hertzbeat.manager.service.ObjectStoreService; + +/** + * Alibaba cloud storage service + */ +@Slf4j +public class OssObjectStoreServiceImpl implements ObjectStoreService { + + private final OSS ossClient; + + private final String bucketName; + private final String rootPath; + + public OssObjectStoreServiceImpl(OSS ossClient, String bucketName, String rootPath) { + this.ossClient = ossClient; + this.bucketName = bucketName; + if (rootPath.startsWith(SignConstants.RIGHT_DASH)) { + this.rootPath = rootPath.substring(1); + } else { + this.rootPath = rootPath; + } + } + + @Override + public boolean upload(String filePath, InputStream is) { + var objectKey = getObjectKey(filePath); + var response = ossClient.putObject(bucketName, objectKey, is); + return Objects.equals(response.getResponse().getStatusCode(), 200); + } + + @Override + public FileDTO download(String filePath) { + var objectKey = getObjectKey(filePath); + try { + var ossObject = ossClient.getObject(bucketName, objectKey); + return new FileDTO(filePath, ossObject.getObjectContent()); + } catch (Exception ex) { + log.warn("download file from oss error {}", objectKey); + return null; + } + } + + @Override + public List list(String dir) { + var request = new ListObjectsRequest(bucketName); + request.setPrefix(getObjectKey(dir)); + return ossClient.listObjects(request).getObjectSummaries().stream() + .map(OSSObjectSummary::getKey).toList().stream() + .map(k -> new FileDTO(k, ossClient.getObject(bucketName, k).getObjectContent())).toList(); + } + + @Override + public ObjectStoreDTO.Type type() { + return ObjectStoreDTO.Type.OSS; + } + + + private String getObjectKey(String filePath) { + return rootPath + SignConstants.RIGHT_DASH + filePath; + } +} diff --git a/web-app/src/app/pojo/ObjectStore.ts b/web-app/src/app/pojo/ObjectStore.ts index d8faed5ed85..915fa9dc149 100644 --- a/web-app/src/app/pojo/ObjectStore.ts +++ b/web-app/src/app/pojo/ObjectStore.ts @@ -32,7 +32,11 @@ export enum ObjectStoreType { /** * 华为云OBS */ - OBS = 'OBS' + OBS = 'OBS', + /** + * Alibaba Cloud OSS + */ + OSS = 'OSS' } export class ObsConfig { @@ -42,3 +46,11 @@ export class ObsConfig { endpoint!: string; savePath: string = 'hertzbeat'; } + +export class OssConfig { + accessKey!: string; + secretKey!: string; + bucketName!: string; + endpoint!: string; + savePath: string = 'hertzbeat'; +} diff --git a/web-app/src/app/routes/setting/settings/object-store/object-store.component.html b/web-app/src/app/routes/setting/settings/object-store/object-store.component.html index 741fe310126..99a2b6f9d54 100644 --- a/web-app/src/app/routes/setting/settings/object-store/object-store.component.html +++ b/web-app/src/app/routes/setting/settings/object-store/object-store.component.html @@ -32,16 +32,21 @@ > + - + {{ 'settings.object-store.obs.accessKey' | i18n }} - + {{ 'settings.object-store.obs.secretKey' | i18n }} - + {{ 'settings.object-store.obs.bucketName' | i18n }} - + {{ 'settings.object-store.obs.endpoint' | i18n }} - + {{ 'settings.object-store.obs.savePath' | i18n }}