[add] Add parameter validators and their corresponding tests (#3888)

Signed-off-by: aias00 <liuhongyu@apache.org>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Tomsun28 <tomsun28@outlook.com>
This commit is contained in:
aias00
2025-12-06 19:34:47 +08:00
committed by GitHub
co-authored by github-actions[bot] Copilot Tomsun28
parent 3e567e5be6
commit 7727d63451
23 changed files with 1534 additions and 251 deletions
@@ -0,0 +1,44 @@
/*
* 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.component.validator;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
/**
* Parameter validator interface
*/
public interface ParamValidator {
/**
* Check if the validator supports the given parameter type
*
* @param type parameter type
* @return true if supported
*/
boolean support(String type);
/**
* Validate the parameter
*
* @param paramDefine parameter definition
* @param param parameter actual value
* @throws IllegalArgumentException if validation fails
*/
void validate(ParamDefine paramDefine, Param param) throws IllegalArgumentException;
}
@@ -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.component.validator;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Parameter validator manager
*/
@Component
public class ParamValidatorManager {
private final List<ParamValidator> validators;
public ParamValidatorManager(List<ParamValidator> validators) {
this.validators = validators;
}
public void validate(ParamDefine paramDefine, Param param) {
for (ParamValidator validator : validators) {
if (validator.support(paramDefine.getType())) {
validator.validate(paramDefine, param);
return;
}
}
// No validator found for the given type.
throw new IllegalArgumentException("ParamDefine type " + paramDefine.getType() + " is invalid.");
}
}
@@ -0,0 +1,46 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* Array parameter validator
*/
@Component
public class ArrayParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "array".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
String[] arrays = param.getParamValue().split(",");
if (arrays.length == 0) {
throw new IllegalArgumentException("Param field " + paramDefine.getField() + " value "
+ param.getParamValue() + " is invalid arrays value");
}
if (param.getParamValue().startsWith("[") && param.getParamValue().endsWith("]")) {
param.setParamValue(param.getParamValue().substring(1, param.getParamValue().length() - 1));
}
}
}
@@ -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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* Boolean parameter validator
*/
@Component
public class BooleanParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "boolean".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
String booleanValue = param.getParamValue();
if (!"true".equalsIgnoreCase(booleanValue) && !"false".equalsIgnoreCase(booleanValue)) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " value "
+ booleanValue + " is invalid boolean value.");
}
}
}
@@ -0,0 +1,49 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* Host parameter validator that delegates to the common HostParamValidator
*/
@Component
public class HostParamValidatorAdapter implements ParamValidator {
private final org.apache.hertzbeat.common.support.valid.HostParamValidator hostValidator;
public HostParamValidatorAdapter() {
this.hostValidator = new org.apache.hertzbeat.common.support.valid.HostParamValidator();
}
@Override
public boolean support(String type) {
return "host".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
if (!hostValidator.isValid(param.getParamValue(), null)) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " value "
+ param.getParamValue() + " is invalid host value.");
}
}
}
@@ -0,0 +1,45 @@
/*
* 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.component.validator.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* JSON parameter validator
*/
@Component
public class JsonParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "metrics-field".equals(type) || "key-value".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
if (JsonUtil.fromJson(param.getParamValue(), new TypeReference<>() {
}) == null) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " value "
+ param.getParamValue() + " is invalid key-value value");
}
}
}
@@ -0,0 +1,53 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.util.IntervalExpressionUtil;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* Number parameter validator
*/
@Component
public class NumberParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "number".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
Double doubleValue = org.apache.hertzbeat.common.util.CommonUtil.parseStrDouble(param.getParamValue());
if (doubleValue == null) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " type "
+ paramDefine.getType() + " is invalid.");
}
if (paramDefine.getRange() != null) {
if (!IntervalExpressionUtil.validNumberIntervalExpress(doubleValue,
paramDefine.getRange())) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " type "
+ paramDefine.getType() + " over range " + paramDefine.getRange());
}
}
param.setType(CommonConstants.PARAM_TYPE_NUMBER);
}
}
@@ -0,0 +1,54 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* Option parameter validator for radio and checkbox types
*/
@Component
public class OptionParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "radio".equals(type) || "checkbox".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
List<ParamDefine.Option> options = paramDefine.getOptions();
boolean invalid = true;
if (options != null) {
for (ParamDefine.Option option : options) {
if (param.getParamValue().equalsIgnoreCase(option.getValue())) {
invalid = false;
break;
}
}
}
if (invalid) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " value "
+ param.getParamValue() + " is invalid option value");
}
}
}
@@ -0,0 +1,46 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.util.AesUtil;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* Password parameter validator
*/
@Component
public class PasswordParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "password".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
String passwordValue = param.getParamValue();
if (!AesUtil.isCiphertext(passwordValue)) {
passwordValue = AesUtil.aesEncode(passwordValue);
param.setParamValue(passwordValue);
}
param.setType(CommonConstants.PARAM_TYPE_PASSWORD);
}
}
@@ -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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.manager.component.validator.ParamValidator;
import org.springframework.stereotype.Component;
/**
* Text parameter validator
*/
@Component
public class TextParamValidator implements ParamValidator {
@Override
public boolean support(String type) {
return "text".equals(type) || "textarea".equals(type);
}
@Override
public void validate(ParamDefine paramDefine, Param param) {
Short limit = paramDefine.getLimit();
if (limit != null && param.getParamValue().length() > limit) {
throw new IllegalArgumentException("Params field " + paramDefine.getField() + " type "
+ paramDefine.getType() + " over limit " + limit);
}
}
}
@@ -0,0 +1,85 @@
/*
* 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.helper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.constants.ExportFileConstants;
import org.apache.hertzbeat.common.constants.SignConstants;
import org.apache.hertzbeat.common.util.FileUtil;
import org.apache.hertzbeat.manager.config.ManagerSseManager;
import org.apache.hertzbeat.manager.service.ImExportService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Helper class for monitor import and export operations
*/
@Component
@Slf4j
public class MonitorImExportHelper {
private static final String CONTENT_VALUE = MediaType.APPLICATION_OCTET_STREAM_VALUE + SignConstants.SINGLE_MARK
+ "charset=" + StandardCharsets.UTF_8;
private final Map<String, ImExportService> imExportServiceMap = new HashMap<>();
private final ManagerSseManager managerSseManager;
public MonitorImExportHelper(List<ImExportService> imExportServiceList, ManagerSseManager managerSseManager) {
imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), it));
this.managerSseManager = managerSseManager;
}
public void export(List<Long> ids, String type, HttpServletResponse res) throws Exception {
var imExportService = imExportServiceMap.get(type);
if (imExportService == null) {
throw new IllegalArgumentException("not support export type: " + type);
}
var fileName = imExportService.getFileName();
res.setHeader(HttpHeaders.CONTENT_DISPOSITION, CONTENT_VALUE);
res.setContentType(CONTENT_VALUE);
res.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
res.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
imExportService.exportConfig(res.getOutputStream(), ids);
}
public void importConfig(MultipartFile file) throws Exception {
var fileName = FileUtil.getFileName(file);
var type = FileUtil.getFileType(file);
try {
if (!imExportServiceMap.containsKey(type)) {
String errMsg = ExportFileConstants.FILE + " " + fileName + " is not supported.";
throw new RuntimeException(errMsg);
}
var imExportService = imExportServiceMap.get(type);
imExportService.importConfig(fileName, file.getInputStream());
} catch (Exception e) {
managerSseManager.broadcastImportTaskFail(fileName, e.getMessage());
throw e;
}
}
}
@@ -17,7 +17,6 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Sets;
import com.google.common.primitives.Longs;
import com.usthe.sureness.subject.SubjectSum;
@@ -29,8 +28,6 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dao.AlertDefineBindDao;
import org.apache.hertzbeat.collector.dispatch.DispatchConstants;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.constants.ExportFileConstants;
import org.apache.hertzbeat.common.constants.NetworkConstants;
import org.apache.hertzbeat.common.constants.SignConstants;
import org.apache.hertzbeat.common.entity.grafana.GrafanaDashboard;
import org.apache.hertzbeat.common.entity.job.Configmap;
@@ -45,15 +42,11 @@ import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
import org.apache.hertzbeat.common.util.AesUtil;
import org.apache.hertzbeat.common.util.FileUtil;
import org.apache.hertzbeat.common.util.IntervalExpressionUtil;
import org.apache.hertzbeat.common.util.IpDomainUtil;
import org.apache.hertzbeat.common.util.JexlCheckerUtil;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
import org.apache.hertzbeat.grafana.service.DashboardService;
import org.apache.hertzbeat.manager.config.ManagerSseManager;
import org.apache.hertzbeat.manager.component.validator.ParamValidatorManager;
import org.apache.hertzbeat.manager.dao.CollectorDao;
import org.apache.hertzbeat.manager.dao.CollectorMonitorBindDao;
import org.apache.hertzbeat.manager.dao.LabelDao;
@@ -65,10 +58,10 @@ import org.apache.hertzbeat.manager.pojo.dto.MetricsInfo;
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
import org.apache.hertzbeat.manager.scheduler.CollectJobScheduling;
import org.apache.hertzbeat.manager.service.AppService;
import org.apache.hertzbeat.manager.service.ImExportService;
import org.apache.hertzbeat.manager.service.LabelService;
import org.apache.hertzbeat.manager.service.MetricsFavoriteService;
import org.apache.hertzbeat.manager.service.MonitorService;
import org.apache.hertzbeat.manager.service.helper.MonitorImExportHelper;
import org.apache.hertzbeat.manager.support.exception.MonitorDatabaseException;
import org.apache.hertzbeat.manager.support.exception.MonitorDetectException;
import org.apache.hertzbeat.warehouse.service.WarehouseService;
@@ -79,16 +72,12 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
@@ -113,8 +102,10 @@ public class MonitorServiceImpl implements MonitorService {
private static final byte ALL_MONITOR_STATUS = 9;
public static final String PARAM_FIELD_PORT = "port";
private static final String CONTENT_VALUE = MediaType.APPLICATION_OCTET_STREAM_VALUE + SignConstants.SINGLE_MARK + "charset=" + StandardCharsets.UTF_8;
private final Map<String, ImExportService> imExportServiceMap = new HashMap<>();
@Autowired
private ParamValidatorManager paramValidatorManager;
@Autowired
private MonitorImExportHelper monitorImExportHelper;
@Autowired
private AppService appService;
@Autowired
@@ -138,18 +129,12 @@ public class MonitorServiceImpl implements MonitorService {
@Autowired
private DashboardService dashboardService;
@Autowired
private ManagerSseManager managerSseManager;
@Autowired
private LabelDao labelDao;
@Autowired
private LabelService labelService;
@Autowired
private MetricsFavoriteService metricsFavoriteService;
public MonitorServiceImpl(List<ImExportService> imExportServiceList) {
imExportServiceList.forEach(it -> imExportServiceMap.put(it.type(), it));
}
@Override
@Transactional(readOnly = true)
public void detectMonitor(Monitor monitor, List<Param> params, String collector) throws MonitorDetectException {
@@ -162,7 +147,8 @@ public class MonitorServiceImpl implements MonitorService {
@Override
@Transactional(rollbackFor = Exception.class)
public void addMonitor(Monitor monitor, List<Param> params, String collector, GrafanaDashboard grafanaDashboard) throws RuntimeException {
public void addMonitor(Monitor monitor, List<Param> params, String collector, GrafanaDashboard grafanaDashboard)
throws RuntimeException {
// Apply for monitor id
long monitorId = SnowFlakeIdGenerator.generateId();
Map<String, String> labels = monitor.getLabels();
@@ -177,7 +163,8 @@ public class MonitorServiceImpl implements MonitorService {
}
// Construct the collection task Job entity
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || !StringUtils.hasText(monitor.getScrape());
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
|| !StringUtils.hasText(monitor.getScrape());
String app = isStatic ? monitor.getApp() : monitor.getScrape();
Job appDefine = appService.getAppDefine(app);
if (!isStatic) {
@@ -199,7 +186,8 @@ public class MonitorServiceImpl implements MonitorService {
.findFirst()
.orElse(null);
String portWithMark = (Objects.isNull(portParam) || !StringUtils.hasText(portParam.getParamValue()))
? "" : SignConstants.DOUBLE_MARK + portParam.getParamValue();
? ""
: SignConstants.DOUBLE_MARK + portParam.getParamValue();
if (Objects.nonNull(instance)) {
instance = instance + portWithMark;
}
@@ -215,11 +203,12 @@ public class MonitorServiceImpl implements MonitorService {
return new Configmap(param.getField(), param.getParamValue(), param.getType());
}).collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
long jobId = collector == null ? collectJobScheduling.addAsyncCollectJob(appDefine, null) :
collectJobScheduling.addAsyncCollectJob(appDefine, collector);
long jobId = collector == null ? collectJobScheduling.addAsyncCollectJob(appDefine, null)
: collectJobScheduling.addAsyncCollectJob(appDefine, collector);
try {
detectMonitor(monitor, params, collector);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
try {
if (collector != null) {
@@ -232,7 +221,8 @@ public class MonitorServiceImpl implements MonitorService {
monitor.setId(monitorId);
monitor.setJobId(jobId);
// create grafana dashboard
if (monitor.getApp().equals(CommonConstants.PROMETHEUS) && grafanaDashboard != null && grafanaDashboard.isEnabled()) {
if (monitor.getApp().equals(CommonConstants.PROMETHEUS) && grafanaDashboard != null
&& grafanaDashboard.isEnabled()) {
dashboardService.createOrUpdateDashboard(grafanaDashboard.getTemplate(), monitorId);
}
monitorDao.save(monitor);
@@ -246,16 +236,7 @@ public class MonitorServiceImpl implements MonitorService {
@Override
public void export(List<Long> ids, String type, HttpServletResponse res) throws Exception {
var imExportService = imExportServiceMap.get(type);
if (imExportService == null) {
throw new IllegalArgumentException("not support export type: " + type);
}
var fileName = imExportService.getFileName();
res.setHeader(HttpHeaders.CONTENT_DISPOSITION, CONTENT_VALUE);
res.setContentType(CONTENT_VALUE);
res.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
res.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
imExportService.exportConfig(res.getOutputStream(), ids);
monitorImExportHelper.export(ids, type, res);
}
@Override
@@ -265,32 +246,21 @@ public class MonitorServiceImpl implements MonitorService {
.stream()
.map(Monitor::getId)
.collect(Collectors.toList());
// Use the existing export method to export all monitors
export(allMonitorIds, type, res);
}
@Override
public void importConfig(MultipartFile file) throws Exception {
var fileName = FileUtil.getFileName(file);
var type = FileUtil.getFileType(file);
try {
if (!imExportServiceMap.containsKey(type)) {
String errMsg = ExportFileConstants.FILE + " " + fileName + " is not supported.";
throw new RuntimeException(errMsg);
}
var imExportService = imExportServiceMap.get(type);
imExportService.importConfig(fileName, file.getInputStream());
} catch (Exception e){
managerSseManager.broadcastImportTaskFail(fileName, e.getMessage());
throw e;
}
monitorImExportHelper.importConfig(file);
}
@Override
@Transactional(readOnly = true)
public void validate(MonitorDto monitorDto, Boolean isModify) throws IllegalArgumentException {
// The request monitoring parameter matches the monitoring parameter definition mapping check
// The request monitoring parameter matches the monitoring parameter definition
// mapping check
Monitor monitor = monitorDto.getMonitor();
// The Service Discovery host field may be null
monitor.setInstance(StringUtils.hasText(monitor.getInstance()) ? monitor.getInstance().trim() : null);
@@ -303,7 +273,7 @@ public class MonitorServiceImpl implements MonitorService {
param.setParamValue(value);
})
.collect(Collectors.toMap(Param::getField, param -> param));
// Check name uniqueness and can not equal app type
// Check name uniqueness and can not equal app type
if (isModify != null) {
Optional<Job> defineOptional = appService.getAppDefineOption(monitor.getName());
if (defineOptional.isPresent()) {
@@ -333,7 +303,8 @@ public class MonitorServiceImpl implements MonitorService {
// Parameter definition structure verification
List<ParamDefine> paramDefines = appService.getAppParamDefines(monitorDto.getMonitor().getApp());
if (!CollectionUtils.isEmpty(paramDefines)) {
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || !StringUtils.hasText(monitor.getScrape());
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
|| !StringUtils.hasText(monitor.getScrape());
for (ParamDefine paramDefine : paramDefines) {
String field = paramDefine.getField();
Param param = paramMap.get(field);
@@ -345,123 +316,7 @@ public class MonitorServiceImpl implements MonitorService {
throw new IllegalArgumentException("Params field " + field + " is required.");
}
if (param != null && StringUtils.hasText(param.getParamValue())) {
switch (paramDefine.getType()) {
case "number":
double doubleValue;
try {
doubleValue = Double.parseDouble(param.getParamValue());
} catch (Exception e) {
throw new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " is invalid.");
}
if (paramDefine.getRange() != null) {
if (!IntervalExpressionUtil.validNumberIntervalExpress(doubleValue,
paramDefine.getRange())) {
throw new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " over range " + paramDefine.getRange());
}
}
param.setType(CommonConstants.PARAM_TYPE_NUMBER);
break;
case "textarea":
Short textareaLimit = paramDefine.getLimit();
if (textareaLimit != null && param.getParamValue().length() > textareaLimit) {
throw new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " over limit " + param.getParamValue());
}
break;
case "text":
Short textLimit = paramDefine.getLimit();
if (textLimit != null && param.getParamValue().length() > textLimit) {
throw new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " over limit " + textLimit);
}
break;
case "host":
String hostValue = param.getParamValue();
if (hostValue.toLowerCase().contains(NetworkConstants.HTTP_HEADER)) {
hostValue = hostValue.replaceAll(PATTERN_HTTP, SignConstants.BLANK);
}
if (hostValue.toLowerCase().contains(NetworkConstants.HTTPS_HEADER)) {
hostValue = hostValue.replace(PATTERN_HTTPS, SignConstants.BLANK);
}
if (!IpDomainUtil.validateIpDomain(hostValue)) {
throw new IllegalArgumentException("Params field " + field + " value "
+ hostValue + " is invalid host value.");
}
break;
case "password":
// The plaintext password needs to be encrypted for transmission and storage
String passwordValue = param.getParamValue();
if (!AesUtil.isCiphertext(passwordValue)) {
passwordValue = AesUtil.aesEncode(passwordValue);
param.setParamValue(passwordValue);
}
param.setType(CommonConstants.PARAM_TYPE_PASSWORD);
break;
case "boolean":
// boolean check
String booleanValue = param.getParamValue();
if (!"true".equalsIgnoreCase(booleanValue) && !"false".equalsIgnoreCase(booleanValue)) {
throw new IllegalArgumentException("Params field " + field + " value "
+ booleanValue + " is invalid boolean value.");
}
break;
case "radio":
// radio single value check
List<ParamDefine.Option> options = paramDefine.getOptions();
boolean invalid = true;
if (options != null) {
for (ParamDefine.Option option : options) {
if (param.getParamValue().equalsIgnoreCase(option.getValue())) {
invalid = false;
break;
}
}
}
if (invalid) {
throw new IllegalArgumentException("Params field " + field + " value "
+ param.getParamValue() + " is invalid option value");
}
break;
case "checkbox":
List<ParamDefine.Option> checkboxOptions = paramDefine.getOptions();
boolean checkboxInvalid = true;
if (checkboxOptions != null) {
for (ParamDefine.Option option : checkboxOptions) {
if (param.getParamValue().equalsIgnoreCase(option.getValue())) {
checkboxInvalid = false;
break;
}
}
}
if (checkboxInvalid) {
throw new IllegalArgumentException("Params field " + field + " value "
+ param.getParamValue() + " is invalid checkbox value");
}
break;
case "metrics-field":
case "key-value":
if (JsonUtil.fromJson(param.getParamValue(), new TypeReference<>() {
}) == null) {
throw new IllegalArgumentException("Params field " + field + " value "
+ param.getParamValue() + " is invalid key-value value");
}
break;
case "array":
String[] arrays = param.getParamValue().split(",");
if (arrays.length == 0) {
throw new IllegalArgumentException("Param field" + field + " value "
+ param.getParamValue() + " is invalid arrays value");
}
if (param.getParamValue().startsWith("[") && param.getParamValue().endsWith("]")) {
param.setParamValue(param.getParamValue().substring(1, param.getParamValue().length() - 1));
}
break;
// todo More parameter definitions and actual value format verification
default:
throw new IllegalArgumentException("ParamDefine type " + paramDefine.getType() + " is invalid.");
}
paramValidatorManager.validate(paramDefine, param);
}
}
}
@@ -485,7 +340,8 @@ public class MonitorServiceImpl implements MonitorService {
}
if (JexlCheckerUtil.verifyStartCharacter(field.getField())) {
throw new IllegalArgumentException(job.getApp() + " " + metrics.getName() + " "
+ field.getField() + " illegal start character, please modify the template information.");
+ field.getField()
+ " illegal start character, please modify the template information.");
}
if (JexlCheckerUtil.verifySpaces(field.getField())) {
throw new IllegalArgumentException(job.getApp() + " " + metrics.getName() + " "
@@ -498,7 +354,8 @@ public class MonitorServiceImpl implements MonitorService {
@Override
@Transactional(rollbackFor = Exception.class)
public void modifyMonitor(Monitor monitor, List<Param> params, String collector, GrafanaDashboard grafanaDashboard) throws RuntimeException {
public void modifyMonitor(Monitor monitor, List<Param> params, String collector, GrafanaDashboard grafanaDashboard)
throws RuntimeException {
long monitorId = monitor.getId();
// Check to determine whether the monitor corresponding to the monitor id exists
Optional<Monitor> queryOption = monitorDao.findById(monitorId);
@@ -529,13 +386,15 @@ public class MonitorServiceImpl implements MonitorService {
.findFirst()
.orElse(null);
String portWithMark = (Objects.isNull(portParam) || !StringUtils.hasText(portParam.getParamValue()))
? "" : SignConstants.DOUBLE_MARK + portParam.getParamValue();
? ""
: SignConstants.DOUBLE_MARK + portParam.getParamValue();
if (Objects.nonNull(instance)) {
instance = instance + portWithMark;
}
monitor.setInstance(instance);
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || !StringUtils.hasText(monitor.getScrape());
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
|| !StringUtils.hasText(monitor.getScrape());
if (preMonitor.getStatus() != CommonConstants.MONITOR_PAUSED_CODE) {
// Construct the collection task Job entity
String app = isStatic ? monitor.getApp() : monitor.getScrape();
@@ -558,8 +417,9 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
List<Configmap> configmaps = params.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(), param.getType()))
.collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
long newJobId;
if (collector == null) {
@@ -572,7 +432,8 @@ public class MonitorServiceImpl implements MonitorService {
// execute only in non paused status
try {
detectMonitor(monitor, params, collector);
} catch (Exception ignored) {}
} catch (Exception ignored) {
}
}
// After the update is successfully released, refresh the database
@@ -584,7 +445,8 @@ public class MonitorServiceImpl implements MonitorService {
.build();
collectorMonitorBindDao.save(collectorMonitorBind);
}
// force update gmtUpdate time, due the case: monitor not change, param change. we also think monitor change
// force update gmtUpdate time, due the case: monitor not change, param change.
// we also think monitor change
monitor.setGmtUpdate(LocalDateTime.now());
// update or open grafana dashboard
if (monitor.getApp().equals(CommonConstants.PROMETHEUS) && grafanaDashboard != null) {
@@ -616,7 +478,8 @@ public class MonitorServiceImpl implements MonitorService {
if (CollectionUtils.isEmpty(ids)) {
return;
}
Set<Long> subMonitorIds = monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId).collect(Collectors.toSet());
Set<Long> subMonitorIds = monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId)
.collect(Collectors.toSet());
Set<Long> allMonitorIds = new HashSet<>(ids);
allMonitorIds.addAll(subMonitorIds);
List<Monitor> monitors = monitorDao.findMonitorsByIdIn(allMonitorIds);
@@ -656,24 +519,29 @@ public class MonitorServiceImpl implements MonitorService {
List<Param> params = paramDao.findParamsByMonitorId(id);
monitorDto.setParams(params);
List<MetricsInfo> metricsInfos;
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(monitor.getApp()) || monitor.getType() == CommonConstants.MONITOR_TYPE_PUSH_AUTO_CREATE) {
if (DispatchConstants.PROTOCOL_PROMETHEUS.equalsIgnoreCase(monitor.getApp())
|| monitor.getType() == CommonConstants.MONITOR_TYPE_PUSH_AUTO_CREATE) {
List<CollectRep.MetricsData> metricsDataList = warehouseService.queryMonitorMetricsData(id);
metricsInfos = metricsDataList.stream()
.map(t -> MetricsInfo.builder().name(t.getMetrics()).favorited(favoritedMetrics.contains(t.getMetrics())).build())
.map(t -> MetricsInfo.builder().name(t.getMetrics())
.favorited(favoritedMetrics.contains(t.getMetrics())).build())
.collect(Collectors.toList());
monitorDto.setGrafanaDashboard(dashboardService.getDashboardByMonitorId(id));
} else {
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || !StringUtils.hasText(monitor.getScrape());
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
|| !StringUtils.hasText(monitor.getScrape());
String type = isStatic ? monitor.getApp() : monitor.getScrape();
Job job = appService.getAppDefine(type);
metricsInfos = job.getMetrics().stream()
.filter(Metrics::isVisible)
.map(t -> MetricsInfo.builder().name(t.getName()).favorited(favoritedMetrics.contains(t.getName())).build())
.map(t -> MetricsInfo.builder().name(t.getName())
.favorited(favoritedMetrics.contains(t.getName())).build())
.collect(Collectors.toList());
}
monitorDto.setMetrics(metricsInfos);
monitorDto.setMonitor(monitor);
Optional<CollectorMonitorBind> bindOptional = collectorMonitorBindDao.findCollectorMonitorBindByMonitorId(monitor.getId());
Optional<CollectorMonitorBind> bindOptional = collectorMonitorBindDao
.findCollectorMonitorBindByMonitorId(monitor.getId());
bindOptional.ifPresent(bind -> monitorDto.setCollector(bind.getCollector()));
return monitorDto;
} else {
@@ -682,7 +550,8 @@ public class MonitorServiceImpl implements MonitorService {
}
@Override
public Page<Monitor> getMonitors(List<Long> monitorIds, String app, String search, Byte status, String sort, String order, int pageIndex, int pageSize, String labels) {
public Page<Monitor> getMonitors(List<Long> monitorIds, String app, String search, Byte status, String sort,
String order, int pageIndex, int pageSize, String labels) {
Specification<Monitor> specification = (root, query, criteriaBuilder) -> {
List<Predicate> andList = new ArrayList<>();
if (!CollectionUtils.isEmpty(monitorIds)) {
@@ -706,7 +575,8 @@ public class MonitorServiceImpl implements MonitorService {
List<Predicate> orList = new ArrayList<>();
if (StringUtils.hasText(search)) {
Predicate predicateHost = criteriaBuilder.like(root.get("host"), "%" + search + "%");
Predicate predicateName = criteriaBuilder.like(criteriaBuilder.lower(root.get("name")), "%" + search.toLowerCase() + "%");
Predicate predicateName = criteriaBuilder.like(criteriaBuilder.lower(root.get("name")),
"%" + search.toLowerCase() + "%");
Long id = Longs.tryParse(search);
if (id != null) {
orList.add(criteriaBuilder.equal(root.get("id"), id));
@@ -754,12 +624,13 @@ public class MonitorServiceImpl implements MonitorService {
return;
}
// Update monitoring status Delete corresponding monitoring periodic task
// The jobId is not deleted, and the jobId is reused again after the management is started.
Set<Long> subMonitorIds = monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId).collect(Collectors.toSet());
// The jobId is not deleted, and the jobId is reused again after the management
// is started.
Set<Long> subMonitorIds = monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId)
.collect(Collectors.toSet());
ids.addAll(subMonitorIds);
List<Monitor> managedMonitors = monitorDao.findMonitorsByIdIn(ids)
.stream().filter(monitor ->
monitor.getStatus() != CommonConstants.MONITOR_PAUSED_CODE)
.stream().filter(monitor -> monitor.getStatus() != CommonConstants.MONITOR_PAUSED_CODE)
.peek(monitor -> monitor.setStatus(CommonConstants.MONITOR_PAUSED_CODE))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(managedMonitors)) {
@@ -773,11 +644,11 @@ public class MonitorServiceImpl implements MonitorService {
@Override
public void enableManageMonitors(Set<Long> ids) {
// Update monitoring status Add corresponding monitoring periodic task
Set<Long> subMonitorIds = monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId).collect(Collectors.toSet());
Set<Long> subMonitorIds = monitorBindDao.findMonitorBindsByBizIdIn(ids).stream().map(MonitorBind::getMonitorId)
.collect(Collectors.toSet());
ids.addAll(subMonitorIds);
List<Monitor> unManagedMonitors = monitorDao.findMonitorsByIdIn(ids)
.stream().filter(monitor ->
monitor.getStatus() == CommonConstants.MONITOR_PAUSED_CODE)
.stream().filter(monitor -> monitor.getStatus() == CommonConstants.MONITOR_PAUSED_CODE)
.peek(monitor -> monitor.setStatus(CommonConstants.MONITOR_UP_CODE))
.collect(Collectors.toList());
if (unManagedMonitors.isEmpty()) {
@@ -787,7 +658,8 @@ public class MonitorServiceImpl implements MonitorService {
for (Monitor monitor : unManagedMonitors) {
// Construct the collection task Job entity
List<Param> params = paramDao.findParamsByMonitorId(monitor.getId());
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape()) || !StringUtils.hasText(monitor.getScrape());
boolean isStatic = CommonConstants.SCRAPE_STATIC.equals(monitor.getScrape())
|| !StringUtils.hasText(monitor.getScrape());
String app = isStatic ? monitor.getApp() : monitor.getScrape();
Job appDefine = appService.getAppDefine(app);
if (!isStatic) {
@@ -807,22 +679,24 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
List<Configmap> configmaps = params.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(), param.getType()))
.collect(Collectors.toList());
List<ParamDefine> paramDefaultValue = appDefine.getParams().stream()
.filter(item -> StringUtils.hasText(item.getDefaultValue()))
.toList();
paramDefaultValue.forEach(defaultVar -> {
if (configmaps.stream().noneMatch(item -> item.getKey().equals(defaultVar.getField()))) {
Configmap configmap = new Configmap(defaultVar.getField(), defaultVar.getDefaultValue(), CommonConstants.TYPE_STRING);
Configmap configmap = new Configmap(defaultVar.getField(), defaultVar.getDefaultValue(),
CommonConstants.TYPE_STRING);
configmaps.add(configmap);
}
});
appDefine.setConfigmap(configmaps);
// Issue collection tasks
Optional<CollectorMonitorBind> bindOptional =
collectorMonitorBindDao.findCollectorMonitorBindByMonitorId(monitor.getId());
Optional<CollectorMonitorBind> bindOptional = collectorMonitorBindDao
.findCollectorMonitorBindByMonitorId(monitor.getId());
String collector = bindOptional.map(CollectorMonitorBind::getCollector).orElse(null);
long newJobId = collectJobScheduling.addAsyncCollectJob(appDefine, collector);
monitor.setJobId(newJobId);
@@ -841,24 +715,26 @@ public class MonitorServiceImpl implements MonitorService {
if (CollectionUtils.isEmpty(appCounts)) {
return null;
}
//Statistical category information, calculate the number of corresponding states for each monitor
// Statistical category information, calculate the number of corresponding
// states for each monitor
Map<String, AppCount> appCountMap = new HashMap<>(appCounts.size());
for (AppCount item : appCounts) {
AppCount appCount = appCountMap.getOrDefault(item.getApp(), new AppCount());
appCount.setApp(item.getApp());
switch (item.getStatus()) {
case CommonConstants.MONITOR_UP_CODE ->
appCount.setAvailableSize(appCount.getAvailableSize() + item.getSize());
appCount.setAvailableSize(appCount.getAvailableSize() + item.getSize());
case CommonConstants.MONITOR_DOWN_CODE ->
appCount.setUnAvailableSize(appCount.getUnAvailableSize() + item.getSize());
appCount.setUnAvailableSize(appCount.getUnAvailableSize() + item.getSize());
case CommonConstants.MONITOR_PAUSED_CODE ->
appCount.setUnManageSize(appCount.getUnManageSize() + item.getSize());
appCount.setUnManageSize(appCount.getUnManageSize() + item.getSize());
default -> {
}
}
appCountMap.put(item.getApp(), appCount);
}
//Traverse the map obtained by statistics and convert it into a List<App Count> result set
// Traverse the map obtained by statistics and convert it into a List<App Count>
// result set
return appCountMap.values().stream().map(item -> {
item.setSize(item.getAvailableSize() + item.getUnManageSize() + item.getUnAvailableSize());
try {
@@ -911,7 +787,8 @@ public class MonitorServiceImpl implements MonitorService {
.toList();
paramDefaultValue.forEach(defaultVar -> {
if (configmaps.stream().noneMatch(item -> item.getKey().equals(defaultVar.getField()))) {
Configmap configmap = new Configmap(defaultVar.getField(), defaultVar.getDefaultValue(), (byte) 1);
Configmap configmap = new Configmap(defaultVar.getField(), defaultVar.getDefaultValue(),
(byte) 1);
configmaps.add(configmap);
}
});
@@ -927,7 +804,7 @@ public class MonitorServiceImpl implements MonitorService {
}
}
}
@Override
public Monitor getMonitor(Long monitorId) {
return monitorDao.findById(monitorId).orElse(null);
@@ -978,7 +855,6 @@ public class MonitorServiceImpl implements MonitorService {
addMonitor(newMonitor, newParams, null, null);
}
private void detectSdMonitor(Monitor monitor, List<Param> params, String collector) {
Long monitorId = monitor.getId();
if (monitorId == null || monitorId == 0) {
@@ -995,8 +871,9 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
List<Configmap> configmaps = params.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(), param.getType()))
.collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
appDefine.setSd(true);
List<CollectRep.MetricsData> collectRep;
@@ -1035,10 +912,12 @@ public class MonitorServiceImpl implements MonitorService {
appDefine.setMetadata(metadata);
appDefine.setLabels(monitor.getLabels());
appDefine.setAnnotations(monitor.getAnnotations());
List<Configmap> configmaps = params.stream().map(param ->
new Configmap(param.getField(), param.getParamValue(), param.getType())).collect(Collectors.toList());
List<Configmap> configmaps = params.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(), param.getType()))
.collect(Collectors.toList());
appDefine.setConfigmap(configmaps);
// To detect availability, you only need to collect the set of availability metrics with a priority of 0.
// To detect availability, you only need to collect the set of availability
// metrics with a priority of 0.
List<Metrics> availableMetrics = appDefine.getMetrics().stream()
.filter(item -> item.getPriority() == 0).collect(Collectors.toList());
appDefine.setMetrics(availableMetrics);
@@ -0,0 +1,72 @@
/*
* 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.component.validator;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ParamValidatorManagerTest {
private ParamValidatorManager paramValidatorManager;
@Mock
private ParamValidator paramValidator;
@BeforeEach
void setUp() {
paramValidatorManager = new ParamValidatorManager(List.of(paramValidator));
}
@Test
void validate_Success() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("text");
Param param = new Param();
when(paramValidator.support("text")).thenReturn(true);
assertDoesNotThrow(() -> paramValidatorManager.validate(paramDefine, param));
verify(paramValidator).validate(paramDefine, param);
}
@Test
void validate_NoValidatorFound() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("unknown");
Param param = new Param();
when(paramValidator.support("unknown")).thenReturn(false);
assertThrows(IllegalArgumentException.class, () -> paramValidatorManager.validate(paramDefine, param));
}
}
@@ -0,0 +1,74 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ArrayParamValidatorTest {
private ArrayParamValidator validator;
@BeforeEach
void setUp() {
validator = new ArrayParamValidator();
}
@Test
void support() {
assertTrue(validator.support("array"));
}
@Test
void validate_ValidArray() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("array");
Param param = new Param();
param.setParamValue("val1,val2");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_ValidArrayWithBrackets() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("array");
Param param = new Param();
param.setParamValue("[val1,val2]");
validator.validate(paramDefine, param);
assertEquals("val1,val2", param.getParamValue());
}
@Test
void validate_EmptyArray() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("array");
paramDefine.setField("tags");
Param param = new Param();
param.setParamValue("");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
assertEquals("", param.getParamValue());
}
}
@@ -0,0 +1,85 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class BooleanParamValidatorTest {
private BooleanParamValidator validator;
@BeforeEach
void setUp() {
validator = new BooleanParamValidator();
}
@Test
void support() {
assertTrue(validator.support("boolean"));
}
@Test
void validate_True() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("boolean");
Param param = new Param();
param.setParamValue("true");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_False() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("boolean");
Param param = new Param();
param.setParamValue("false");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_CaseInsensitive() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("boolean");
Param param = new Param();
param.setParamValue("True");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_Invalid() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("boolean");
paramDefine.setField("ssl");
Param param = new Param();
param.setParamValue("yes");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
}
@@ -0,0 +1,95 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class HostParamValidatorAdapterTest {
private HostParamValidatorAdapter validator;
@BeforeEach
void setUp() {
validator = new HostParamValidatorAdapter();
}
@Test
void support() {
assertTrue(validator.support("host"));
}
@Test
void validate_ValidHost() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("host");
Param param = new Param();
param.setParamValue("127.0.0.1");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_ValidDomain() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("host");
Param param = new Param();
param.setParamValue("localhost");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_HttpPrefix() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("host");
Param param = new Param();
param.setParamValue("http://127.0.0.1");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_InvalidHost() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("host");
paramDefine.setField("host");
Param param = new Param();
param.setParamValue("invalid host");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
@Test
void validate_HostWithPort() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("host");
Param param = new Param();
param.setParamValue("127.0.0.1:8080");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
}
@@ -0,0 +1,66 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class JsonParamValidatorTest {
private JsonParamValidator validator;
@BeforeEach
void setUp() {
validator = new JsonParamValidator();
}
@Test
void support() {
assertTrue(validator.support("metrics-field"));
assertTrue(validator.support("key-value"));
}
@Test
void validate_ValidJson() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("key-value");
Param param = new Param();
param.setParamValue("{\"key\":\"value\"}");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_InvalidJson() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("key-value");
paramDefine.setField("headers");
Param param = new Param();
param.setParamValue("{key:value}"); // Invalid JSON
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
}
@@ -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.component.validator.impl;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class NumberParamValidatorTest {
private NumberParamValidator validator;
@BeforeEach
void setUp() {
validator = new NumberParamValidator();
}
@Test
void support() {
assertTrue(validator.support("number"));
}
@Test
void validate_ValidNumber() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("number");
Param param = new Param();
param.setParamValue("123");
validator.validate(paramDefine, param);
assertEquals(CommonConstants.PARAM_TYPE_NUMBER, param.getType());
}
@Test
void validate_InvalidNumber() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("number");
paramDefine.setField("port");
Param param = new Param();
param.setParamValue("abc");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
@Test
void validate_NumberInRange() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("number");
paramDefine.setRange("[0,100]");
Param param = new Param();
param.setParamValue("50");
validator.validate(paramDefine, param);
}
@Test
void validate_NumberOutOfRange() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("number");
paramDefine.setField("port");
paramDefine.setRange("[0,100]");
Param param = new Param();
param.setParamValue("150");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
}
@@ -0,0 +1,81 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class OptionParamValidatorTest {
private OptionParamValidator validator;
@BeforeEach
void setUp() {
validator = new OptionParamValidator();
}
@Test
void support() {
assertTrue(validator.support("radio"));
assertTrue(validator.support("checkbox"));
}
@Test
void validate_ValidOption() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("radio");
paramDefine.setOptions(List.of(new ParamDefine.Option("opt1", "val1"), new ParamDefine.Option("opt2", "val2")));
Param param = new Param();
param.setParamValue("val1");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_InvalidOption() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("radio");
paramDefine.setField("method");
paramDefine.setOptions(List.of(new ParamDefine.Option("opt1", "val1")));
Param param = new Param();
param.setParamValue("val2");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
@Test
void validate_NullOptions() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("radio");
paramDefine.setField("method");
Param param = new Param();
param.setParamValue("val1");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
}
@@ -0,0 +1,75 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.util.AesUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class PasswordParamValidatorTest {
private PasswordParamValidator validator;
@BeforeEach
void setUp() {
validator = new PasswordParamValidator();
}
@Test
void support() {
assertTrue(validator.support("password"));
}
@Test
void validate_EncryptsPlaintext() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("password");
Param param = new Param();
String plaintext = "password123";
param.setParamValue(plaintext);
validator.validate(paramDefine, param);
assertNotEquals(plaintext, param.getParamValue());
assertTrue(AesUtil.isCiphertext(param.getParamValue()));
assertEquals(CommonConstants.PARAM_TYPE_PASSWORD, param.getType());
}
@Test
void validate_IgnoresCiphertext() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("password");
Param param = new Param();
String ciphertext = AesUtil.aesEncode("password123");
param.setParamValue(ciphertext);
validator.validate(paramDefine, param);
assertEquals(ciphertext, param.getParamValue());
assertEquals(CommonConstants.PARAM_TYPE_PASSWORD, param.getType());
}
}
@@ -0,0 +1,68 @@
/*
* 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.component.validator.impl;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class TextParamValidatorTest {
private TextParamValidator validator;
@BeforeEach
void setUp() {
validator = new TextParamValidator();
}
@Test
void support() {
assertTrue(validator.support("text"));
assertTrue(validator.support("textarea"));
}
@Test
void validate_ValidLength() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("text");
paramDefine.setLimit((short) 10);
Param param = new Param();
param.setParamValue("12345");
assertDoesNotThrow(() -> validator.validate(paramDefine, param));
}
@Test
void validate_OverLimit() {
ParamDefine paramDefine = new ParamDefine();
paramDefine.setType("text");
paramDefine.setField("name");
paramDefine.setLimit((short) 3);
Param param = new Param();
param.setParamValue("12345");
assertThrows(IllegalArgumentException.class, () -> validator.validate(paramDefine, param));
}
}
@@ -50,9 +50,13 @@ import org.apache.hertzbeat.manager.dao.ParamDao;
import org.apache.hertzbeat.manager.pojo.dto.AppCount;
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
import org.apache.hertzbeat.manager.scheduler.CollectJobScheduling;
import org.apache.hertzbeat.manager.component.validator.ParamValidatorManager;
import org.apache.hertzbeat.manager.service.helper.MonitorImExportHelper;
import org.apache.hertzbeat.manager.service.impl.MonitorServiceImpl;
import org.apache.hertzbeat.manager.support.exception.MonitorDatabaseException;
import org.apache.hertzbeat.manager.support.exception.MonitorDetectException;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -73,13 +77,19 @@ import org.springframework.data.jpa.domain.Specification;
* <a href="https://www.cnblogs.com/it1042290135/p/16202478.html">...</a>
* <p>
* <a href="http://clickhouse:9363/metrics">...</a>
* docker run -d --name some-clickhouse-server -p 8123:8123 -p 9009:9009 -p 9090:9000 -p 9363:9363
* --ulimit nofile=262144:262144 --volume=/opt/clickhouse/data:/var/lib/clickhouse --volume=/opt/clickhouse/log:/var/log/clickhouse-server
* --volume=/opt/clickhouse/conf/config.xml:/etc/clickhouse-server/config.xml --volume=/opt/clickhouse/conf/users.xml:/etc/clickhouse-server/users.xml clickhouse/clickhouse-server
* docker run -d --name some-clickhouse-server -p 8123:8123 -p 9009:9009 -p
* 9090:9000 -p 9363:9363
* --ulimit nofile=262144:262144
* --volume=/opt/clickhouse/data:/var/lib/clickhouse
* --volume=/opt/clickhouse/log:/var/log/clickhouse-server
* --volume=/opt/clickhouse/conf/config.xml:/etc/clickhouse-server/config.xml
* --volume=/opt/clickhouse/conf/users.xml:/etc/clickhouse-server/users.xml
* clickhouse/clickhouse-server
* <p>
* <p>
* <a href="https://hub.docker.com/r/clickhouse/clickhouse-server/">...</a>
* docker run -d -p 18123:8123 -p19000:9000 --name some-clickhouse-server --ulimit nofile=262144:262144 clickhouse/clickhouse-server
* docker run -d -p 18123:8123 -p19000:9000 --name some-clickhouse-server
* --ulimit nofile=262144:262144 clickhouse/clickhouse-server
* curl '<a href="http://localhost:18123/">...</a>'
* web UI
* <a href="http://localhost:18123/play">...</a>
@@ -93,7 +103,13 @@ import org.springframework.data.jpa.domain.Specification;
class MonitorServiceTest {
@InjectMocks
private MonitorServiceImpl monitorService = new MonitorServiceImpl(List.of());
private MonitorServiceImpl monitorService;
@Mock
private ParamValidatorManager paramValidatorManager;
@Mock
private MonitorImExportHelper monitorImExportHelper;
@Mock
private MonitorDao monitorDao;
@@ -296,6 +312,8 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
doThrow(new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " is invalid.")).when(paramValidatorManager).validate(any(), any());
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -305,7 +323,8 @@ class MonitorServiceTest {
}
/**
* Parameter verification - This parameter is mandatory. - Integer parameter range
* Parameter verification - This parameter is mandatory. - Integer parameter
* range
*/
@Test
void validateMonitorParamsRange() {
@@ -332,6 +351,9 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
doThrow(new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " over range " + paramDefine.getRange())).when(paramValidatorManager)
.validate(any(), any());
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -369,6 +391,8 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
doThrow(new IllegalArgumentException("Params field " + field + " type "
+ paramDefine.getType() + " over limit " + limit)).when(paramValidatorManager).validate(any(), any());
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -413,6 +437,11 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
if (checkException) {
doThrow(new IllegalArgumentException(
"Params field " + field + " value " + value + " is invalid host value."))
.when(paramValidatorManager).validate(any(), any());
}
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -459,6 +488,10 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
if (checkException) {
doThrow(new IllegalArgumentException("Params field " + field + " value "
+ value + " is invalid boolean value.")).when(paramValidatorManager).validate(any(), any());
}
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -510,6 +543,11 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
if (checkException) {
doThrow(new IllegalArgumentException("Params field " + field + " value "
+ param.getParamValue() + " is invalid option value")).when(paramValidatorManager)
.validate(any(), any());
}
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -561,6 +599,10 @@ class MonitorServiceTest {
.build();
paramDefines.add(paramDefine);
when(appService.getAppParamDefines(monitor.getApp())).thenReturn(paramDefines);
if (checkException) {
doThrow(new IllegalArgumentException("ParamDefine type " + paramDefine.getType() + " is invalid."))
.when(paramValidatorManager).validate(any(), any());
}
try {
monitorService.validate(dto, isModify);
} catch (IllegalArgumentException e) {
@@ -584,7 +626,8 @@ class MonitorServiceTest {
params.add(param);
dto.setParams(params);
long monitorId = 1L;
Monitor monitor = Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host").id(monitorId).build();
Monitor monitor = Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host")
.id(monitorId).build();
dto.setMonitor(monitor);
when(monitorDao.findById(monitorId)).thenReturn(Optional.empty());
try {
@@ -594,7 +637,7 @@ class MonitorServiceTest {
}
reset();
/*
The [monitoring type] of monitor cannot be modified.
* The [monitoring type] of monitor cannot be modified.
*/
Monitor existErrorMonitor = Monitor.builder().app("app2").name("memory").instance("host").id(monitorId).build();
when(monitorDao.findById(monitorId)).thenReturn(Optional.of(existErrorMonitor));
@@ -604,11 +647,13 @@ class MonitorServiceTest {
assertEquals("Can not modify monitor's app type", e.getMessage());
}
reset();
Monitor existOkMonitor = Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host").id(monitorId).build();
Monitor existOkMonitor = Monitor.builder().jobId(1L).intervals(1).app("app").name("memory").instance("host")
.id(monitorId).build();
when(monitorDao.findById(monitorId)).thenReturn(Optional.of(existOkMonitor));
when(monitorDao.save(monitor)).thenThrow(RuntimeException.class);
assertThrows(MonitorDatabaseException.class, () -> monitorService.modifyMonitor(dto.getMonitor(), dto.getParams(), null, null));
assertThrows(MonitorDatabaseException.class,
() -> monitorService.modifyMonitor(dto.getMonitor(), dto.getParams(), null, null));
}
@Test
@@ -617,7 +662,8 @@ class MonitorServiceTest {
ids.add(1L);
List<Monitor> monitors = new ArrayList<>();
for (Long id : ids) {
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
.build();
monitors.add(monitor);
}
when(monitorDao.findMonitorsByIdIn(ids)).thenReturn(monitors);
@@ -633,7 +679,8 @@ class MonitorServiceTest {
List<Monitor> monitors = new ArrayList<>();
for (Long id : ids) {
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
.build();
monitors.add(monitor);
}
when(monitorDao.findMonitorsByIdIn(ids)).thenReturn(monitors);
@@ -643,7 +690,8 @@ class MonitorServiceTest {
@Test
void getMonitorDto() {
long id = 1L;
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
.build();
when(monitorDao.findById(id)).thenReturn(Optional.of(monitor));
List<Param> params = Collections.singletonList(new Param());
when(paramDao.findParamsByMonitorId(id)).thenReturn(params);
@@ -657,7 +705,7 @@ class MonitorServiceTest {
@Test
void getMonitors() {
when(monitorDao.findAll(any(Specification.class), any(PageRequest.class))).thenAnswer((invocation)->{
when(monitorDao.findAll(any(Specification.class), any(PageRequest.class))).thenAnswer((invocation) -> {
Specification<Monitor> spec = invocation.getArgument(0);
CriteriaBuilder cb = mock(CriteriaBuilder.class);
CriteriaQuery<?> query = mock(CriteriaQuery.class);
@@ -677,7 +725,8 @@ class MonitorServiceTest {
List<Monitor> monitors = new ArrayList<>();
for (Long id : ids) {
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
.build();
monitors.add(monitor);
}
when(monitorDao.findMonitorsByIdIn(ids)).thenReturn(monitors);
@@ -692,7 +741,8 @@ class MonitorServiceTest {
List<Monitor> monitors = new ArrayList<>();
for (Long id : ids) {
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id).build();
Monitor monitor = Monitor.builder().jobId(id).intervals(1).app("app").name("memory").instance("host").id(id)
.build();
monitor.setStatus(CommonConstants.MONITOR_PAUSED_CODE);
monitors.add(monitor);
}
@@ -716,7 +766,6 @@ class MonitorServiceTest {
appCounts.add(appCount);
when(monitorDao.findAppsStatusCount()).thenReturn(appCounts);
Job job = new Job();
job.setMetrics(new ArrayList<>());
when(appService.getAppDefine(appCounts.get(0).getApp())).thenReturn(job);
@@ -768,26 +817,17 @@ class MonitorServiceTest {
Monitor monitor1 = Monitor.builder().id(1L).name("test1").app("app1").build();
Monitor monitor2 = Monitor.builder().id(2L).name("test2").app("app2").build();
List<Monitor> allMonitors = List.of(monitor1, monitor2);
// Mock the behavior of monitorDao.findAll
when(monitorDao.findAll()).thenReturn(allMonitors);
// Create a mock HttpServletResponse
jakarta.servlet.http.HttpServletResponse mockResponse = org.mockito.Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
// Mock the ImExportService
org.apache.hertzbeat.manager.service.ImExportService mockImExportService = org.mockito.Mockito.mock(org.apache.hertzbeat.manager.service.ImExportService.class);
// Mock the getFileName method
when(mockImExportService.getFileName()).thenReturn("test.json");
// Set the field using reflection
java.lang.reflect.Field field = MonitorServiceImpl.class.getDeclaredField("imExportServiceMap");
field.setAccessible(true);
java.util.Map<String, org.apache.hertzbeat.manager.service.ImExportService> imExportServiceMap = new java.util.HashMap<>();
imExportServiceMap.put("JSON", mockImExportService);
field.set(monitorService, imExportServiceMap);
jakarta.servlet.http.HttpServletResponse mockResponse = org.mockito.Mockito
.mock(jakarta.servlet.http.HttpServletResponse.class);
// Test the exportAll method
assertDoesNotThrow(() -> monitorService.exportAll("JSON", mockResponse));
verify(monitorImExportHelper).export(List.of(1L, 2L), "JSON", mockResponse);
}
@Test
@@ -802,8 +842,8 @@ class MonitorServiceTest {
Job job = new Job();
job.setApp("testJob");
job.setMetrics(metrics);
Monitor monitor = Monitor.builder().jobId(1L).intervals(1).app(job.getApp()).name(job.getApp()).instance("host").build();
Monitor monitor = Monitor.builder().jobId(1L).intervals(1).app(job.getApp()).name(job.getApp()).instance("host")
.build();
List<Param> params = new ArrayList<>();
params.add(Param.builder().field("field").paramValue("value").build());
@@ -813,7 +853,9 @@ class MonitorServiceTest {
dto.setParams(params);
when(appService.getAppDefine(monitor.getApp())).thenReturn(job);
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> monitorService.validate(dto, null));
assertEquals("testJob metricsName size prohibited keywords, please modify the template information.", exception.getMessage());
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
() -> monitorService.validate(dto, null));
assertEquals("testJob metricsName size prohibited keywords, please modify the template information.",
exception.getMessage());
}
}
@@ -0,0 +1,100 @@
/*
* 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.helper;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.hertzbeat.manager.config.ManagerSseManager;
import org.apache.hertzbeat.manager.service.ImExportService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MonitorImExportHelperTest {
private MonitorImExportHelper helper;
@Mock
private ImExportService imExportService;
@Mock
private ManagerSseManager managerSseManager;
@BeforeEach
void setUp() {
when(imExportService.type()).thenReturn("JSON");
helper = new MonitorImExportHelper(List.of(imExportService), managerSseManager);
}
@Test
void export_Success() throws Exception {
HttpServletResponse response = mock(HttpServletResponse.class);
ServletOutputStream outputStream = mock(ServletOutputStream.class);
when(response.getOutputStream()).thenReturn(outputStream);
when(imExportService.getFileName()).thenReturn("test.json");
helper.export(List.of(1L), "JSON", response);
verify(imExportService).exportConfig(eq(outputStream), anyList());
}
@Test
void export_UnsupportedType() {
HttpServletResponse response = mock(HttpServletResponse.class);
assertThrows(IllegalArgumentException.class, () -> helper.export(List.of(1L), "XML", response));
}
@Test
void importConfig_Success() throws Exception {
MultipartFile file = mock(MultipartFile.class);
when(file.getOriginalFilename()).thenReturn("test.json");
InputStream inputStream = new ByteArrayInputStream("{}".getBytes());
when(file.getInputStream()).thenReturn(inputStream);
helper.importConfig(file);
verify(imExportService).importConfig(eq("test.json"), any(InputStream.class));
}
@Test
void importConfig_UnsupportedType() {
MultipartFile file = mock(MultipartFile.class);
when(file.getOriginalFilename()).thenReturn("test.xml");
assertThrows(RuntimeException.class, () -> helper.importConfig(file));
verify(managerSseManager).broadcastImportTaskFail(eq("test.xml"), any());
}
}