diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/DispatcherAlarm.java b/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/DispatcherAlarm.java index 0e688e1c7ce..c543c08a1ca 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/DispatcherAlarm.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/component/alerter/DispatcherAlarm.java @@ -131,7 +131,7 @@ public void run() { // Notice distribution sendNotify(alert); // Execute the plugin if enable - pluginService.pluginExecute(Plugin.class, plugin -> plugin.alert(alert)); + pluginService.pluginExecute(Plugin.class, plugin -> plugin.alert(alert), (plugin, configMapList) -> plugin.alert(alert, configMapList)); } } catch (IgnoreException ignored) { } catch (InterruptedException e) { diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/controller/PluginController.java b/manager/src/main/java/org/apache/hertzbeat/manager/controller/PluginController.java index 1fb73ada760..18c24544fac 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/controller/PluginController.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/controller/PluginController.java @@ -27,6 +27,8 @@ import org.apache.hertzbeat.common.entity.dto.Message; import org.apache.hertzbeat.common.entity.dto.PluginUpload; import org.apache.hertzbeat.common.entity.manager.PluginMetadata; +import org.apache.hertzbeat.manager.pojo.dto.PluginParam; +import org.apache.hertzbeat.manager.pojo.dto.PluginParametersVO; import org.apache.hertzbeat.manager.service.PluginService; import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; @@ -85,4 +87,19 @@ public ResponseEntity> updatePluginStatus(@RequestBody PluginMetad pluginService.updateStatus(plugin); return ResponseEntity.ok(Message.success("Update success")); } + + @GetMapping("/params/define") + @Operation(summary = "get param define", description = "get param define by jar path") + public ResponseEntity> getParamDefine(@RequestParam Long pluginMetadataId) { + PluginParametersVO plugins = pluginService.getParamDefine(pluginMetadataId); + return ResponseEntity.ok(Message.success(plugins)); + } + + @PostMapping("/params") + @Operation(summary = "get param define", description = "get param define by jar path") + public ResponseEntity> saveParams(@RequestBody List pluginParams) { + pluginService.savePluginParam(pluginParams); + return ResponseEntity.ok(Message.success(true)); + } + } diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/dao/PluginParamDao.java b/manager/src/main/java/org/apache/hertzbeat/manager/dao/PluginParamDao.java new file mode 100644 index 00000000000..4eeec26b192 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/dao/PluginParamDao.java @@ -0,0 +1,48 @@ +/* + * 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.dao; + +import java.util.List; +import java.util.Set; +import org.apache.hertzbeat.manager.pojo.dto.PluginParam; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * PluginParamDao database operations + */ +public interface PluginParamDao extends JpaRepository { + + /** + * Query the list of parameters associated with the monitoring ID' + * @param pluginMetadataId Monitor ID + * @return list of parameter values + */ + List findParamsByPluginMetadataId(Long pluginMetadataId); + + /** + * Remove the parameter list associated with the pluginMetadata ID based on it + * @param pluginMetadataId Monitor Id + */ + void deletePluginParamsByPluginMetadataId(long pluginMetadataId); + + /** + * Remove the parameter list associated with the pluginMetadata ID list based on it + * @param pluginMetadataIds Monitoring ID List + */ + void deletePluginParamsByPluginMetadataIdIn(Set pluginMetadataIds); +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java b/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java new file mode 100644 index 00000000000..b92948f2b10 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParam.java @@ -0,0 +1,110 @@ +/* + * 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.pojo.dto; + +import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY; +import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_WRITE; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +/** + * PluginParam + */ +@Entity +@Table(name = "hzb_plugin_param", indexes = { @Index(columnList = "pluginMetadataId") }, + uniqueConstraints = @UniqueConstraint(columnNames = {"pluginMetadataId", "field"})) +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "Parameter Entity") +@EntityListeners(AuditingEntityListener.class) +public class PluginParam { + + /** + * Parameter primary key index ID + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Schema(title = "Parameter primary key index ID", example = "87584674384", accessMode = READ_ONLY) + private Long id; + /** + * Monitor ID + */ + @Schema(title = "Plugin task ID", example = "875846754543", accessMode = READ_WRITE) + @NotNull + private Long pluginMetadataId; + + /** + * Parameter Field Identifier + */ + @Schema(title = "Parameter identifier field", example = "port", accessMode = READ_WRITE) + @Size(max = 100) + @NotNull + private String field; + + /** + * Param Value + */ + @Schema(title = "parameter values", example = "8080", accessMode = READ_WRITE) + @Size(max = 8126) + @Column(length = 8126) + private String paramValue; + + /** + * Parameter type 0: number 1: string 2: encrypted string 3: json string mapped by map + */ + @Schema(title = "Parameter types 0: number 1: string 2: encrypted string 3:map mapped json string 4:arrays string", + accessMode = READ_WRITE) + @Min(0) + private byte type; + + /** + * Record create time + */ + @Schema(title = "Record create time", example = "1612198922000", accessMode = READ_ONLY) + @CreatedDate + private LocalDateTime gmtCreate; + + /** + * Record the latest modification time + */ + @Schema(title = "Record modify time", example = "1612198444000", accessMode = READ_ONLY) + @LastModifiedDate + private LocalDateTime gmtUpdate; + +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParametersVO.java b/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParametersVO.java new file mode 100644 index 00000000000..ba3f2f9ffa1 --- /dev/null +++ b/manager/src/main/java/org/apache/hertzbeat/manager/pojo/dto/PluginParametersVO.java @@ -0,0 +1,43 @@ +/* + * 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.pojo.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.hertzbeat.common.entity.manager.ParamDefine; +import java.util.List; + +/** + * Popup rendering and parameter values + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PluginParametersVO { + + /** + * Stencil rendering + */ + private List paramDefines; + + /** + * specific parameter + */ + private List pluginParams; +} diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/PluginService.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/PluginService.java index 23d01a30be2..a7f0c706e4f 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/service/PluginService.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/PluginService.java @@ -17,10 +17,15 @@ package org.apache.hertzbeat.manager.service; +import java.util.List; import java.util.Set; +import java.util.function.BiConsumer; import java.util.function.Consumer; import org.apache.hertzbeat.common.entity.dto.PluginUpload; +import org.apache.hertzbeat.common.entity.job.Configmap; import org.apache.hertzbeat.common.entity.manager.PluginMetadata; +import org.apache.hertzbeat.manager.pojo.dto.PluginParam; +import org.apache.hertzbeat.manager.pojo.dto.PluginParametersVO; import org.springframework.data.domain.Page; /** @@ -58,7 +63,7 @@ public interface PluginService { * @param execute run plugin logic * @param plugin type */ - void pluginExecute(Class clazz, Consumer execute); + void pluginExecute(Class clazz, Consumer execute, BiConsumer> biConsumer); /** * delete plugin @@ -69,4 +74,16 @@ public interface PluginService { void updateStatus(PluginMetadata plugin); + /** + * get param define + * @param pluginMetadataId plugin id + */ + PluginParametersVO getParamDefine(Long pluginMetadataId); + + /** + * save plugin param + * @param params params + */ + void savePluginParam(List params); + } diff --git a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java index 162d4bc394a..4ccae0fd0ed 100644 --- a/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java +++ b/manager/src/main/java/org/apache/hertzbeat/manager/service/impl/PluginServiceImpl.java @@ -39,9 +39,11 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -49,17 +51,26 @@ import org.apache.commons.io.FileUtils; import org.apache.hertzbeat.common.constants.PluginType; import org.apache.hertzbeat.common.entity.dto.PluginUpload; +import org.apache.hertzbeat.common.entity.job.Configmap; +import org.apache.hertzbeat.common.entity.manager.ParamDefine; import org.apache.hertzbeat.common.entity.manager.PluginItem; import org.apache.hertzbeat.common.entity.manager.PluginMetadata; import org.apache.hertzbeat.common.support.exception.CommonException; import org.apache.hertzbeat.manager.dao.PluginItemDao; import org.apache.hertzbeat.manager.dao.PluginMetadataDao; +import org.apache.hertzbeat.manager.dao.PluginParamDao; +import org.apache.hertzbeat.manager.pojo.dto.PluginParam; +import org.apache.hertzbeat.manager.pojo.dto.PluginParametersVO; import org.apache.hertzbeat.manager.service.PluginService; import org.apache.hertzbeat.plugin.Plugin; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.error.YAMLException; /** * plugin service @@ -73,6 +84,8 @@ public class PluginServiceImpl implements PluginService { private final PluginItemDao itemDao; + private final PluginParamDao pluginParamDao; + public static Map, PluginType> PLUGIN_TYPE_MAPPING = new HashMap<>(); /** @@ -80,10 +93,25 @@ public class PluginServiceImpl implements PluginService { */ private static final Map PLUGIN_ENABLE_STATUS = new ConcurrentHashMap<>(); + /** + * plugin param define + */ + private static final Map> PARAMS_DEFINE_MAP = new ConcurrentHashMap<>(); + + /** + * plugin params + */ + private static final Map> PARAMS_MAP = new ConcurrentHashMap<>(); + + /** + * pluginItem Mapping pluginId + */ + private static final Map ITEM_TO_PLUGINMETADATAID_MAP = new ConcurrentHashMap<>(); private final List pluginClassLoaders = new ArrayList<>(); @Override + @Transactional public void deletePlugins(Set ids) { List plugins = metadataDao.findAllById(ids); // disable the plugins that need to be removed @@ -106,11 +134,13 @@ public void deletePlugins(Set ids) { } // delete metadata metadataDao.deleteById(plugin.getId()); + syncPluginParamMap(plugin.getId(), null, true); } catch (IOException e) { throw new RuntimeException(e); } } + pluginParamDao.deletePluginParamsByPluginMetadataIdIn(ids); syncPluginStatus(); // reload classloader loadJarToClassLoader(); @@ -139,6 +169,40 @@ public void updateStatus(PluginMetadata plugin) { } } + @Override + public PluginParametersVO getParamDefine(Long pluginMetadataId) { + + PluginParametersVO pluginParametersVO = new PluginParametersVO(); + if (PARAMS_DEFINE_MAP.containsKey(pluginMetadataId)) { + List paramDefines = PARAMS_DEFINE_MAP.get(pluginMetadataId); + List paramsByPluginMetadataId = pluginParamDao.findParamsByPluginMetadataId(pluginMetadataId); + pluginParametersVO.setParamDefines(paramDefines); + pluginParametersVO.setPluginParams(paramsByPluginMetadataId); + return pluginParametersVO; + } + return pluginParametersVO; + } + + @Override + @Transactional + public void savePluginParam(List params) { + if (CollectionUtils.isEmpty(params)) { + return; + } + pluginParamDao.deletePluginParamsByPluginMetadataId(params.get(0).getPluginMetadataId()); + pluginParamDao.saveAll(params); + syncPluginParamMap(params.get(0).getPluginMetadataId(), params, false); + } + + private void syncPluginParamMap(Long pluginMetadataId, List params, boolean isDelete) { + if (isDelete) { + PARAMS_MAP.remove(pluginMetadataId); + return; + } + List configmapList = params.stream().map(item -> new Configmap(item.getField(), item.getParamValue(), item.getType())).toList(); + PARAMS_MAP.put(pluginMetadataId, configmapList); + } + static { PLUGIN_TYPE_MAPPING.put(Plugin.class, PluginType.POST_ALERT); } @@ -154,8 +218,9 @@ public List validateJarFile(File jarFile) { try { URL jarUrl = new URL("file:" + jarFile.getAbsolutePath()); try (URLClassLoader classLoader = new URLClassLoader(new URL[]{jarUrl}, this.getClass().getClassLoader()); - JarFile jar = new JarFile(jarFile)) { + JarFile jar = new JarFile(jarFile)) { Enumeration entries = jar.entries(); + Yaml yaml = new Yaml(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); if (entry.getName().endsWith(".class")) { @@ -173,6 +238,11 @@ public List validateJarFile(File jarFile) { System.err.println("Failed to load class: " + className); } } + if ((entry.getName().contains("define")) && (entry.getName().endsWith(".yml") || entry.getName().endsWith(".yaml"))) { + try (InputStream ymlInputStream = jar.getInputStream(entry)) { + yaml.loadAs(ymlInputStream, List.class); + } + } } if (pluginItems.isEmpty()) { throw new CommonException("Illegal plug-ins, please refer to https://hertzbeat.apache.org/docs/help/plugin/"); @@ -184,6 +254,8 @@ public List validateJarFile(File jarFile) { } catch (MalformedURLException e) { log.error("Invalid JAR file URL: {}", jarFile.getAbsoluteFile(), e); throw new CommonException("Invalid JAR file URL: " + jarFile.getAbsolutePath()); + } catch (YAMLException e) { + throw new CommonException("YAML the file format is incorrect"); } return pluginItems; } @@ -196,6 +268,7 @@ private void validateMetadata(PluginMetadata metadata) { @Override @SneakyThrows + @Transactional public void savePlugin(PluginUpload pluginUpload) { String jarPath = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()).getAbsolutePath(); Path extLibPath = Paths.get(new File(jarPath).getParent(), "plugin-lib"); @@ -268,13 +341,33 @@ public Page getPlugins(String search, int pageIndex, int pageSiz private void syncPluginStatus() { List plugins = metadataDao.findAll(); Map statusMap = new HashMap<>(); + Map itemToPluginMetadataIdMap = new HashMap<>(); for (PluginMetadata plugin : plugins) { for (PluginItem item : plugin.getItems()) { statusMap.put(item.getClassIdentifier(), plugin.getEnableStatus()); + itemToPluginMetadataIdMap.put(item.getClassIdentifier(), plugin.getId()); } } PLUGIN_ENABLE_STATUS.clear(); PLUGIN_ENABLE_STATUS.putAll(statusMap); + ITEM_TO_PLUGINMETADATAID_MAP.clear(); + ITEM_TO_PLUGINMETADATAID_MAP.putAll(itemToPluginMetadataIdMap); + } + + @PostConstruct + private void initParams(){ + try { + List params = pluginParamDao.findAll(); + Map> content = params.stream() + .collect(Collectors.groupingBy(PluginParam::getPluginMetadataId)); + + for (Map.Entry> entry : content.entrySet()) { + syncPluginParamMap(entry.getKey(), entry.getValue(), false); + } + } catch (Exception e) { + log.error("Failed to init params:{}", e.getMessage()); + throw new CommonException("Failed to init params:" + e.getMessage()); + } } /** @@ -288,14 +381,19 @@ private void loadJarToClassLoader() { pluginClassLoader.close(); } } - pluginClassLoaders.clear(); - System.gc(); + + if (!pluginClassLoaders.isEmpty()) { + pluginClassLoaders.clear(); + System.gc(); + } + PARAMS_DEFINE_MAP.clear(); List plugins = metadataDao.findPluginMetadataByEnableStatusTrue(); for (PluginMetadata metadata : plugins) { - List urls = loadLibInPlugin(metadata.getJarFilePath()); + List urls = loadLibInPlugin(metadata.getJarFilePath(), metadata.getId()); urls.add(new File(metadata.getJarFilePath()).toURI().toURL()); pluginClassLoaders.add(new URLClassLoader(urls.toArray(new URL[0]), Plugin.class.getClassLoader())); } + } catch (MalformedURLException e) { log.error("Failed to load plugin:{}", e.getMessage()); throw new CommonException("Failed to load plugin:" + e.getMessage()); @@ -308,19 +406,24 @@ private void loadJarToClassLoader() { * loading other JAR files that are dependencies for the plugin * * @param pluginJarPath jar file path + * @param pluginMetadataId plugin id * @return urls */ @SneakyThrows - private List loadLibInPlugin(String pluginJarPath) { + private List loadLibInPlugin(String pluginJarPath, Long pluginMetadataId) { File libDir = new File(getOtherLibDir(pluginJarPath)); FileUtils.forceMkdir(libDir); List libUrls = new ArrayList<>(); try (JarFile jarFile = new JarFile(pluginJarPath)) { Enumeration entries = jarFile.entries(); + Yaml yaml = new Yaml(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); File file = new File(libDir, entry.getName()); - if (!entry.isDirectory() && entry.getName().endsWith(".jar")) { + if (entry.isDirectory()) { + continue; + } + if (entry.getName().endsWith(".jar")) { if (!file.getParentFile().exists()) { FileUtils.createParentDirectories(file); } @@ -335,18 +438,30 @@ private List loadLibInPlugin(String pluginJarPath) { out.flush(); } } + if ((entry.getName().contains("define")) && (entry.getName().endsWith(".yml") || entry.getName().endsWith(".yaml"))) { + try (InputStream ymlInputStream = jarFile.getInputStream(entry)) { + List params = yaml.loadAs(ymlInputStream, List.class); + PARAMS_DEFINE_MAP.put(pluginMetadataId, params); + } + } } } return libUrls; } @Override - public void pluginExecute(Class clazz, Consumer execute) { + public void pluginExecute(Class clazz, Consumer execute, BiConsumer> biConsumer) { for (URLClassLoader pluginClassLoader : pluginClassLoaders) { ServiceLoader load = ServiceLoader.load(clazz, pluginClassLoader); for (T t : load) { if (pluginIsEnable(t.getClass())) { - execute.accept(t); + Long pluginId = ITEM_TO_PLUGINMETADATAID_MAP.get(t.getClass().getName()); + List configmapList = PARAMS_MAP.get(pluginId); + if (CollectionUtils.isEmpty(configmapList)) { + execute.accept(t); + } else { + biConsumer.accept(t, configmapList); + } } } } diff --git a/manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java b/manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java index 2fbfa72a667..59dc49b2014 100644 --- a/manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java +++ b/manager/src/test/java/org/apache/hertzbeat/manager/service/PluginServiceTest.java @@ -39,6 +39,7 @@ import org.apache.hertzbeat.common.entity.manager.PluginMetadata; import org.apache.hertzbeat.manager.dao.PluginItemDao; import org.apache.hertzbeat.manager.dao.PluginMetadataDao; +import org.apache.hertzbeat.manager.dao.PluginParamDao; import org.apache.hertzbeat.manager.service.impl.PluginServiceImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -60,16 +61,20 @@ class PluginServiceTest { @InjectMocks private PluginServiceImpl pluginService; + @Mock private PluginMetadataDao metadataDao; + @Mock + private PluginParamDao pluginParamDao; + @Mock private PluginItemDao itemDao; @BeforeEach void setUp() { - pluginService = new PluginServiceImpl(metadataDao, itemDao); + pluginService = new PluginServiceImpl(metadataDao, itemDao, pluginParamDao); } @Test diff --git a/plugin/src/main/java/org/apache/hertzbeat/plugin/Plugin.java b/plugin/src/main/java/org/apache/hertzbeat/plugin/Plugin.java index d72632925b5..efeed504603 100644 --- a/plugin/src/main/java/org/apache/hertzbeat/plugin/Plugin.java +++ b/plugin/src/main/java/org/apache/hertzbeat/plugin/Plugin.java @@ -17,7 +17,9 @@ package org.apache.hertzbeat.plugin; +import java.util.List; import org.apache.hertzbeat.common.entity.alerter.Alert; +import org.apache.hertzbeat.common.entity.job.Configmap; /** * Plugin @@ -28,4 +30,10 @@ public interface Plugin { * execute when alert */ void alert(Alert alert); + + /** + * Supports user-defined parameters + */ + void alert(Alert alert, List params); + } diff --git a/plugin/src/main/resources/define/define.yml b/plugin/src/main/resources/define/define.yml new file mode 100644 index 00000000000..25b47f6ad57 --- /dev/null +++ b/plugin/src/main/resources/define/define.yml @@ -0,0 +1,14 @@ +# 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. diff --git a/web-app/src/app/routes/setting/plugins/plugin.component.html b/web-app/src/app/routes/setting/plugins/plugin.component.html index fd749ed975a..4bf3bffd295 100644 --- a/web-app/src/app/routes/setting/plugins/plugin.component.html +++ b/web-app/src/app/routes/setting/plugins/plugin.component.html @@ -92,6 +92,9 @@
+
+ + +
+
+ + + {{ paramDefine.name }} + + + + + +
+
+
diff --git a/web-app/src/app/routes/setting/plugins/plugin.component.ts b/web-app/src/app/routes/setting/plugins/plugin.component.ts index 0ac42a2ed80..142a7533f49 100644 --- a/web-app/src/app/routes/setting/plugins/plugin.component.ts +++ b/web-app/src/app/routes/setting/plugins/plugin.component.ts @@ -27,6 +27,7 @@ import { NzTableQueryParams } from 'ng-zorro-antd/table'; import { NzUploadFile } from 'ng-zorro-antd/upload'; import { finalize } from 'rxjs/operators'; +import { ParamDefine } from '../../../pojo/ParamDefine'; import { Plugin } from '../../../pojo/Plugin'; import { PluginService } from '../../../service/plugin.service'; @@ -47,8 +48,10 @@ export class SettingPluginsComponent implements OnInit { jarFile: [null, [Validators.required]], enableStatus: [true, [Validators.required]] }); + this.lang = this.i18nSvc.defaultLang; } + lang: string; pageIndex: number = 1; pageSize: number = 8; total: number = 0; @@ -275,4 +278,63 @@ export class SettingPluginsComponent implements OnInit { }); this.fileList = []; } + + params: any = {}; + paramDefines!: ParamDefine[]; + isEditPluginParamDefineModalVisible = false; + + onEditPluginParamDefine(pluginId: number) { + const getPluginParamDefine$ = this.pluginService + .getPluginParamDefine(pluginId) + .pipe( + finalize(() => { + getPluginParamDefine$.unsubscribe(); + }) + ) + .subscribe((message: any) => { + if (message.code === 0) { + this.paramDefines = message.data.paramDefines.map((i: any) => { + this.params[i.field] = { + pluginMetadataId: pluginId, + // Parameter type 0: number 1: string 2: encrypted string 3: json string mapped by map + type: i.type === 'number' ? 0 : i.type === 'text' || i.type === 'string' ? 1 : i.type === 'json' ? 3 : 2, + field: i.field, + paramValue: this.getParamValue(message.data.pluginParams, i.field) + }; + i.name = i.name[this.lang]; + return i; + }); + this.isEditPluginParamDefineModalVisible = true; + } else { + this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg); + } + }); + } + + onEditPluginParamDefineModalCancel() { + this.isEditPluginParamDefineModalVisible = false; + } + + onEditPluginParamDefineModalOk() { + const savePluginParamDefine$ = this.pluginService + .savePluginParamDefine(Object.values(this.params)) + .pipe( + finalize(() => { + savePluginParamDefine$.unsubscribe(); + }) + ) + .subscribe((message: any) => { + if (message.code === 0) { + this.isEditPluginParamDefineModalVisible = false; + this.notifySvc.success(this.i18nSvc.fanyi('common.notify.edit-success'), ''); + } else { + this.notifySvc.error(this.i18nSvc.fanyi('common.notify.edit-fail'), message.msg); + } + }); + } + + getParamValue(pluginParams: any[], field: string) { + const pluginParam = (pluginParams || []).filter((i: any) => i.field === field); + return pluginParam.length > 0 ? pluginParam[0].paramValue : null; + } } diff --git a/web-app/src/app/service/plugin.service.ts b/web-app/src/app/service/plugin.service.ts index 90278805dbc..1b34ed5cb50 100644 --- a/web-app/src/app/service/plugin.service.ts +++ b/web-app/src/app/service/plugin.service.ts @@ -64,20 +64,6 @@ export class PluginService { return this.http.put>(plugin_uri, body); } - public newTags(body: Tag[]): Observable> { - return this.http.post>(plugin_uri, body); - } - - public newTag(body: Tag): Observable> { - const tags = []; - tags.push(body); - return this.http.post>(plugin_uri, tags); - } - - public editTag(body: Tag): Observable> { - return this.http.put>(plugin_uri, body); - } - public deletePlugins(pluginIds: Set): Observable> { let httpParams = new HttpParams(); pluginIds.forEach(pluginId => { @@ -86,4 +72,17 @@ export class PluginService { const options = { params: httpParams }; return this.http.delete>(plugin_uri, options); } + + public getPluginParamDefine(pluginId: number): Observable> { + let httpParams = new HttpParams(); + httpParams = httpParams.appendAll({ + pluginMetadataId: pluginId + }); + const options = { params: httpParams }; + return this.http.get>(`${plugin_uri}/params/define`, options); + } + + public savePluginParamDefine(body: any): Observable> { + return this.http.post>(`${plugin_uri}/params`, body); + } } diff --git a/web-app/src/app/shared/components/form-field/form-field.component.html b/web-app/src/app/shared/components/form-field/form-field.component.html index 0362b7973e3..8b61e8141d4 100644 --- a/web-app/src/app/shared/components/form-field/form-field.component.html +++ b/web-app/src/app/shared/components/form-field/form-field.component.html @@ -18,7 +18,7 @@ --> You can also click \"New Monitor Type\" to custom define an new type. Currently supported protocols include HTTP, JDBC, SSH, JMX, SNMP. Monitor Templates.", "define.help.link": "https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-point/", "define.save-apply": "Save And Apply", diff --git a/web-app/src/assets/i18n/zh-CN.json b/web-app/src/assets/i18n/zh-CN.json index 57306828029..1603c6af17e 100644 --- a/web-app/src/assets/i18n/zh-CN.json +++ b/web-app/src/assets/i18n/zh-CN.json @@ -564,6 +564,7 @@ "plugin.type": "插件类型", "plugin.type.POST_ALERT": "告警后", "plugin.search": "搜索插件", + "plugin.edit": "编辑插件", "define.help": "监控模版定义每一个监控类型,类型的参数变量,指标信息,采集协议等。您可根据需求在下拉菜单中选择已有监控模板修改。左下区域为对照区,右下区域为编辑区。
您也可以点击“新增监控类型”来自定义新的的监控类型,目前支持 HTTP 协议JDBC协议SSH协议 JMX 协议 SNMP 协议点击查看监控模板。\n", "define.help.link": "https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-point/", "define.save-apply": "保存并应用", diff --git a/web-app/src/assets/i18n/zh-TW.json b/web-app/src/assets/i18n/zh-TW.json index dfdc25251f1..6f974a620fe 100644 --- a/web-app/src/assets/i18n/zh-TW.json +++ b/web-app/src/assets/i18n/zh-TW.json @@ -577,6 +577,7 @@ "plugin.delete": "刪除插件", "plugin.type.POST_ALERT": "告警後", "plugin.search": "搜尋插件", + "plugin.edit": "編輯插件", "define.help": "監控模版定義每一個監控類型,類型的參數變量,指標信息,採集協議等。您可根據需求在下拉功能表中選擇已有監控模版進行修改。右下區域為編輯區,左下區域為對照區。
您也可以點擊“新增監控類型”來自定義新的的監控類型,現支持 HTTP協議JDBC協定SSH協定 JMX協定 SNMP協定點擊查看監控範本。", "define.help.link": "https://hertzbeat.apache.org/zh-cn/docs/advanced/extend-point/", "define.save-apply": "保存並應用",