Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions sofa-boot-project/sofa-boot-actuator-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
package com.alipay.sofa.boot.actuator.autoconfigure.health;

import com.alipay.sofa.boot.actuator.health.HealthCheckerConfig;
import jakarta.validation.constraints.Positive;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.HashMap;
Expand All @@ -33,6 +35,7 @@
* Created on 2020/5/18
*/
@ConfigurationProperties("sofa.boot.actuator.health")
@Validated
public class HealthProperties {

/**
Expand All @@ -54,6 +57,7 @@ public class HealthProperties {
/**
* Timeout duration of parallel health check, in milliseconds.
*/
@Positive(message = "Parallel health check timeout must be greater than 0")
private long parallelCheckTimeout = 120 * 1000;

/**
Expand Down Expand Up @@ -84,6 +88,7 @@ public class HealthProperties {
/**
* Global {@link com.alipay.sofa.boot.actuator.health.HealthChecker} health check timeout,in milliseconds.
*/
@Positive(message = "Global HealthChecker timeout must be greater than 0")
private int globalHealthCheckerTimeout = 60 * 1000;

/**
Expand All @@ -95,6 +100,7 @@ public class HealthProperties {
/**
* Global {@link org.springframework.boot.actuate.health.HealthIndicator} health check timeout,in milliseconds.
*/
@Positive(message = "Global HealthIndicator timeout must be greater than 0")
private int globalHealthIndicatorTimeout = 60 * 1000;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.core.NestedExceptionUtils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
Expand Down Expand Up @@ -148,6 +149,17 @@ void customHealthCheckParallelCheck() {
});
}

@Test
void invalidHealthPropertiesShouldFailFast() {
this.contextRunner
.withPropertyValues("sofa.boot.actuator.health.parallelCheckTimeout=0")
.run((context) -> {
assertThat(context).hasFailed();
assertThat(NestedExceptionUtils.getMostSpecificCause(context.getStartupFailure()).getMessage())
.contains("Parallel health check timeout must be greater than 0");
});
}

@Test
void runWhenWithIsleConfiguration() {
this.contextRunner
Expand Down
5 changes: 5 additions & 0 deletions sofa-boot-project/sofa-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
*/
package com.alipay.sofa.boot.autoconfigure.isle;

import jakarta.validation.constraints.Positive;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -28,6 +30,7 @@
* @author huzijie
*/
@ConfigurationProperties("sofa.boot.isle")
@Validated
public class SofaModuleProperties {

/**
Expand Down Expand Up @@ -78,16 +81,19 @@ public class SofaModuleProperties {
/**
* Thead pool size factor used in parallel sofa module application context refresh.
*/
@Positive(message = "Parallel module refresh thread pool size factor must be greater than 0")
private float parallelRefreshPoolSizeFactor = 5.0f;

/**
* Timeout used in parallel sofa module application context refresh, in milliseconds.
*/
@Positive(message = "Parallel module refresh timeout must be greater than 0")
private long parallelRefreshTimeout = 60;

/**
* Monitor period used in parallel sofa module application context refresh, in milliseconds.
*/
@Positive(message = "Parallel module refresh check period must be greater than 0")
private long parallelRefreshCheckPeriod = 30;

public List<String> getActiveProfiles() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import java.util.HashMap;
import java.util.List;
Expand All @@ -33,6 +34,8 @@
* @author khotyn
*/
@ConfigurationProperties("sofa.boot.rpc")
@Validated
@ValidSofaBootRpcProperties
public class SofaBootRpcProperties implements EnvironmentAware {

public static final String PREFIX = "sofa.boot.rpc";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
* 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 com.alipay.sofa.boot.autoconfigure.rpc;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;

/**
* Validator for {@link SofaBootRpcProperties}.
*
* @author huzijie
*/
public class SofaBootRpcPropertiesValidator
implements
ConstraintValidator<ValidSofaBootRpcProperties, SofaBootRpcProperties> {

@Override
public boolean isValid(SofaBootRpcProperties value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
context.disableDefaultConstraintViolation();
boolean valid = true;

valid = validatePort(context, valid, "boltPort", value.getBoltPort(),
"Bolt port must be between 1024 and 65535");
valid = validatePort(context, valid, "h2cPort", value.getH2cPort(),
"H2C port must be between 1024 and 65535");
valid = validatePort(context, valid, "restPort", value.getRestPort(),
Comment on lines +30 to +46

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the verification of rpc need to be handled separately?

"REST port must be between 1024 and 65535");
valid = validatePort(context, valid, "dubboPort", value.getDubboPort(),
"Dubbo port must be between 1024 and 65535");
valid = validatePort(context, valid, "httpPort", value.getHttpPort(),
"HTTP port must be between 1024 and 65535");
valid = validatePort(context, valid, "triplePort", value.getTriplePort(),
"Triple port must be between 1024 and 65535");
valid = validatePort(context, valid, "virtualPort", value.getVirtualPort(),
"Virtual port must be between 1024 and 65535");

valid = validatePositiveInteger(context, valid, "boltThreadPoolCoreSize",
value.getBoltThreadPoolCoreSize(), "Bolt thread pool core size must be greater than 0");
valid = validatePositiveInteger(context, valid, "boltThreadPoolMaxSize",
value.getBoltThreadPoolMaxSize(), "Bolt thread pool max size must be greater than 0");
valid = validatePositiveInteger(context, valid, "boltThreadPoolQueueSize",
value.getBoltThreadPoolQueueSize(),
"Bolt thread pool queue size must be greater than 0");
valid = validatePositiveInteger(context, valid, "boltAcceptsSize",
value.getBoltAcceptsSize(), "Bolt accepts size must be greater than 0");
valid = validatePositiveInteger(context, valid, "h2cThreadPoolCoreSize",
value.getH2cThreadPoolCoreSize(), "H2C thread pool core size must be greater than 0");
valid = validatePositiveInteger(context, valid, "h2cThreadPoolMaxSize",
value.getH2cThreadPoolMaxSize(), "H2C thread pool max size must be greater than 0");
valid = validatePositiveInteger(context, valid, "h2cThreadPoolQueueSize",
value.getH2cThreadPoolQueueSize(), "H2C thread pool queue size must be greater than 0");
valid = validatePositiveInteger(context, valid, "h2cAcceptsSize",
value.getH2cAcceptsSize(), "H2C accepts size must be greater than 0");
valid = validatePositiveInteger(context, valid, "restIoThreadSize",
value.getRestIoThreadSize(), "REST IO thread size must be greater than 0");
valid = validatePositiveInteger(context, valid, "restThreadPoolMaxSize",
value.getRestThreadPoolMaxSize(), "REST thread pool max size must be greater than 0");
valid = validatePositiveInteger(context, valid, "restMaxRequestSize",
value.getRestMaxRequestSize(), "REST max request size must be greater than 0");
valid = validatePositiveInteger(context, valid, "dubboIoThreadSize",
value.getDubboIoThreadSize(), "Dubbo IO thread size must be greater than 0");
valid = validatePositiveInteger(context, valid, "dubboThreadPoolMaxSize",
value.getDubboThreadPoolMaxSize(), "Dubbo thread pool max size must be greater than 0");
valid = validatePositiveInteger(context, valid, "dubboAcceptsSize",
value.getDubboAcceptsSize(), "Dubbo accepts size must be greater than 0");
valid = validatePositiveInteger(context, valid, "httpThreadPoolCoreSize",
value.getHttpThreadPoolCoreSize(), "HTTP thread pool core size must be greater than 0");
valid = validatePositiveInteger(context, valid, "httpThreadPoolMaxSize",
value.getHttpThreadPoolMaxSize(), "HTTP thread pool max size must be greater than 0");
valid = validatePositiveInteger(context, valid, "httpThreadPoolQueueSize",
value.getHttpThreadPoolQueueSize(),
"HTTP thread pool queue size must be greater than 0");
valid = validatePositiveInteger(context, valid, "httpAcceptsSize",
value.getHttpAcceptsSize(), "HTTP accepts size must be greater than 0");
valid = validatePositiveInteger(context, valid, "tripleThreadPoolCoreSize",
value.getTripleThreadPoolCoreSize(),
"Triple thread pool core size must be greater than 0");
valid = validatePositiveInteger(context, valid, "tripleThreadPoolMaxSize",
value.getTripleThreadPoolMaxSize(),
"Triple thread pool max size must be greater than 0");
valid = validatePositiveInteger(context, valid, "tripleThreadPoolQueueSize",
value.getTripleThreadPoolQueueSize(),
"Triple thread pool queue size must be greater than 0");
valid = validatePositiveInteger(context, valid, "tripleAcceptsSize",
value.getTripleAcceptsSize(), "Triple accepts size must be greater than 0");
valid = validatePositiveInteger(context, valid, "consumerRepeatedReferenceLimit",
value.getConsumerRepeatedReferenceLimit(),
"Consumer repeated reference limit must be greater than 0");

valid = validateBooleanString(context, valid, "aftRegulationEffective",
value.getAftRegulationEffective(), "AFT regulation switch must be true or false");
valid = validateBooleanString(context, valid, "aftDegradeEffective",
value.getAftDegradeEffective(), "AFT degrade switch must be true or false");
valid = validateBooleanString(context, valid, "restTelnet", value.getRestTelnet(),
"REST telnet switch must be true or false");
valid = validateBooleanString(context, valid, "restDaemon", value.getRestDaemon(),
"REST daemon switch must be true or false");

valid = validatePositiveInteger(context, valid, "aftTimeWindow", value.getAftTimeWindow(),
"AFT time window must be greater than 0");
valid = validatePositiveInteger(context, valid, "aftLeastWindowCount",
value.getAftLeastWindowCount(), "AFT least window count must be greater than 0");
valid = validatePositiveDecimal(context, valid, "aftLeastWindowExceptionRateMultiple",
value.getAftLeastWindowExceptionRateMultiple(),
"AFT least window exception rate multiple must be greater than 0");
valid = validateRange(context, valid, "aftDegradeLeastWeight",
value.getAftDegradeLeastWeight(), 0, 100,
"AFT degrade least weight must be between 0 and 100");
valid = validatePositiveInteger(context, valid, "aftDegradeMaxIpCount",
value.getAftDegradeMaxIpCount(), "AFT degrade max IP count must be greater than 0");
valid = validateDecimalRange(context, valid, "aftWeightDegradeRate",
value.getAftWeightDegradeRate(), BigDecimal.ZERO, false, BigDecimal.ONE, true,
"AFT weight degrade rate must be greater than 0 and less than or equal to 1");
valid = validatePositiveDecimal(context, valid, "aftWeightRecoverRate",
value.getAftWeightRecoverRate(), "AFT weight recover rate must be greater than 0");

return valid;
}

private boolean validatePort(ConstraintValidatorContext context, boolean valid,
String fieldName, String rawValue, String message) {
return validateRange(context, valid, fieldName, rawValue, 1024, 65535, message);
}

private boolean validatePositiveInteger(ConstraintValidatorContext context, boolean valid,
String fieldName, String rawValue, String message) {
if (!StringUtils.hasText(rawValue)) {
return valid;
}
Integer parsedValue = parseInteger(rawValue);
if (parsedValue == null || parsedValue <= 0) {
addViolation(context, fieldName, message);
return false;
}
return valid;
}

private boolean validateRange(ConstraintValidatorContext context, boolean valid,
String fieldName, String rawValue, int min, int max,
String message) {
if (!StringUtils.hasText(rawValue)) {
return valid;
}
Integer parsedValue = parseInteger(rawValue);
if (parsedValue == null || parsedValue < min || parsedValue > max) {
addViolation(context, fieldName, message);
return false;
}
return valid;
}

private boolean validatePositiveDecimal(ConstraintValidatorContext context, boolean valid,
String fieldName, String rawValue, String message) {
if (!StringUtils.hasText(rawValue)) {
return valid;
}
BigDecimal parsedValue = parseDecimal(rawValue);
if (parsedValue == null || parsedValue.compareTo(BigDecimal.ZERO) <= 0) {
addViolation(context, fieldName, message);
return false;
}
return valid;
}

private boolean validateDecimalRange(ConstraintValidatorContext context, boolean valid,
String fieldName, String rawValue, BigDecimal min,
boolean minInclusive, BigDecimal max,
boolean maxInclusive, String message) {
if (!StringUtils.hasText(rawValue)) {
return valid;
}
BigDecimal parsedValue = parseDecimal(rawValue);
if (parsedValue == null) {
addViolation(context, fieldName, message);
return false;
}

boolean underMin = minInclusive ? parsedValue.compareTo(min) < 0 : parsedValue
.compareTo(min) <= 0;
boolean overMax = maxInclusive ? parsedValue.compareTo(max) > 0 : parsedValue
.compareTo(max) >= 0;
if (underMin || overMax) {
addViolation(context, fieldName, message);
return false;
}
return valid;
}

private boolean validateBooleanString(ConstraintValidatorContext context, boolean valid,
String fieldName, String rawValue, String message) {
if (!StringUtils.hasText(rawValue)) {
return valid;
}
if (!"true".equalsIgnoreCase(rawValue) && !"false".equalsIgnoreCase(rawValue)) {
addViolation(context, fieldName, message);
return false;
}
return valid;
}

private Integer parseInteger(String rawValue) {
try {
return Integer.valueOf(rawValue);
} catch (NumberFormatException ex) {
return null;
}
}

private BigDecimal parseDecimal(String rawValue) {
try {
return new BigDecimal(rawValue);
} catch (NumberFormatException ex) {
return null;
}
}

private void addViolation(ConstraintValidatorContext context, String fieldName, String message) {
context.buildConstraintViolationWithTemplate(message).addPropertyNode(fieldName)
.addConstraintViolation();
}
}
Loading
Loading