Develop Custom Validations
Learn how to develop custom resource validations.
This section covers the core classes to develop validation extensions.
Interface
To create a custom validation
, you will need to implement the Java
interface: io.streamthoughts.jikkou.core.validation.Validation
.
This interface defines two methods, with a default implementation for each, to give you the option of validating either all resources accepted by validation at once, or each resource one by one.
public interface Validation<T extends HasMetadata> extends Interceptor {
/**
* Validates the specified resource list.
*
* @param resources The list of resources to be validated.
* @return The ValidationResult.
*/
default ValidationResult validate(@NotNull final List<T> resources) {
// code omitted for clarity
}
/**
* Validates the specified resource.
*
* @param resource The resource to be validated.
* @return The ValidationResult.
*/
default ValidationResult validate(@NotNull final T resource) {
// code omitted for clarity
}
}
Examples
The validation class below shows how to validate that any resource has a specific non-empty label.
@Title("HasNonEmptyLabelValidation allows validating that resources have a non empty label.")
@Description("This validation can be used to ensure that all resources are associated to a specific label. The labe key is passed through the configuration of the extension.")
@Example(
title = "Validate that resources have a non-empty label with key 'owner'.",
full = true,
code = {"""
validations:
- name: "resourceMustHaveNonEmptyLabelOwner"
type: "com.example.jikkou.validation.HasNonEmptyLabelValidation"
priority: 100
config:
key: owner
"""
}
)
@SupportedResources(value = {}) // an empty list implies that the extension supports any resource-type
public final class HasNonEmptyLabelValidation implements Validation {
// The required config property.
static final ConfigProperty<String> LABEL_KEY_CONFIG = ConfigProperty.ofString("key");
private String key;
/**
* Empty constructor - required.
*/
public HasNonEmptyLabelValidation() {
}
/**
* {@inheritDoc}
*/
@Override
public void configure(@NotNull final Configuration config) {
// Get the key from the configuration.
this.key = LABEL_KEY_CONFIG
.getOptional(config)
.orElseThrow(() -> new ConfigException(
String.format("The '%s' configuration property is required for %s",
LABEL_KEY_CONFIG.key(),
TopicNamePrefixValidation.class.getSimpleName()
)
));
}
/**
* {@inheritDoc}
*/
@Override
public ValidationResult validate(final @NotNull HasMetadata resource) {
Optional<String> label = resource.getMetadata()
.findLabelByKey(this.key)
.map(NamedValue::getValue)
.map(Value::asString)
.filter(String::isEmpty);
// Failure
if (label.isEmpty()) {
String error = String.format(
"Resource for name '%s' have no defined or empty label for key: '%s'",
resource.getMetadata().getName(),
this.key
);
return ValidationResult.failure(new ValidationError(getName(), resource, error));
}
// Success
return ValidationResult.success();
}
}
Last modified November 22, 2023: refactor(core): refactor the ExtensionProvider api (ea44e963)