Skip to content

Commit

Permalink
feat(rules): implement declarative Automated Rules
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewazores committed Dec 19, 2024
1 parent 329fec6 commit 702a425
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/main/docker/Dockerfile.jvm
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ ENTRYPOINT [ "/deployments/app/entrypoint.bash", "/opt/jboss/container/java/run/
# We make distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 src/main/docker/include/cryostat.jfc /usr/lib/jvm/jre/lib/jfr/
COPY --chown=185 src/main/docker/include/template_presets/* /opt/cryostat.d/presets.d/
COPY --chown=185 src/main/docker/include/rule_presets/* /opt/cryostat.d/rules.d/
COPY --chown=185 src/main/docker/include/genpass.bash /deployments/app/
COPY --chown=185 src/main/docker/include/entrypoint.bash /deployments/app/
COPY --chown=185 src/main/docker/include/truststore-setup.bash /deployments/app/
Expand Down
7 changes: 7 additions & 0 deletions src/main/docker/include/rule_presets/quarkus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "quarkus",
"description": "Preset Automated Rule for enabling Quarkus framework-specific events when available",
"eventSpecifier": "template=Quarkus,type=PRESET",
"matchExpression": "jfrEventTypeIds(target).exists(x, x.contains(\"quarkus\"))",
"enabled": false
}
1 change: 1 addition & 0 deletions src/main/java/io/cryostat/ConfigProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class ConfigProperties {
public static final String CUSTOM_TEMPLATES_DIR = "templates-dir";
public static final String PRESET_TEMPLATES_DIR = "preset-templates-dir";
public static final String SSL_TRUSTSTORE_DIR = "ssl.truststore.dir";
public static final String RULES_DIR = "rules-dir";

public static final String URI_RANGE = "cryostat.target.uri-range";
}
74 changes: 74 additions & 0 deletions src/main/java/io/cryostat/rules/Rules.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@
*/
package io.cryostat.rules;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Objects;

import io.cryostat.ConfigProperties;
import io.cryostat.expressions.MatchExpression;
import io.cryostat.util.EntityExistsException;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.runtime.StartupEvent;
import io.vertx.core.json.JsonObject;
import io.vertx.mutiny.core.eventbus.EventBus;
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.BadRequestException;
Expand All @@ -36,6 +44,8 @@
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.UriInfo;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.RestPath;
import org.jboss.resteasy.reactive.RestQuery;
Expand All @@ -45,7 +55,71 @@
@Path("/api/v4/rules")
public class Rules {

@ConfigProperty(name = ConfigProperties.RULES_DIR)
java.nio.file.Path dir;

@Inject Logger logger;
@Inject EventBus bus;
@Inject ObjectMapper mapper;

@Transactional
void onStart(@Observes StartupEvent evt) {
if (!checkDir()) {
return;
}
try {
Files.walk(dir)
.filter(Files::isRegularFile)
.filter(Files::isReadable)
.peek(
p ->
logger.tracev(
"Processing declarative Automated Rule definition at"
+ " {}",
p))
.forEach(this::processDeclarativeRule);
} catch (IOException e) {
logger.error(e);
}
}

private void processDeclarativeRule(java.nio.file.Path path) {
try (var is = new BufferedInputStream(Files.newInputStream(path))) {
var declarativeRule = mapper.readValue(is, Rule.class);
logger.tracev(
"Processing eclarative Automated" + " Rule with name \"{}\"",
declarativeRule.name);
var exists = Rule.find("name", declarativeRule.name).count() != 0;
if (exists) {
var existingRule = Rule.<Rule>find("name", declarativeRule.name).singleResult();
// remove for equality check. The declarative rule is not expected to have a
// database ID yet existingRule.id = null;
if (Objects.equals(declarativeRule, existingRule)) {
return;
}
logger.debugv(
"Rule with name \"{}\" already exists in database. Replacing with"
+ " declarative rule at {}. Previous definition:\n"
+ "{}",
declarativeRule.name,
path,
mapper.writeValueAsString(existingRule));
existingRule.delete();
}
declarativeRule.persist();
} catch (IOException ioe) {
logger.warn(ioe);
} catch (Exception e) {
logger.error(e);
}
}

private boolean checkDir() {
return Files.exists(dir)
&& Files.isReadable(dir)
&& Files.isExecutable(dir)
&& Files.isDirectory(dir);
}

@GET
@RolesAllowed("read")
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ cryostat.http.proxy.path=/
cryostat.target.uri-range=PUBLIC

conf-dir=/opt/cryostat.d
rules-dir=${conf-dir}/rules.d
templates-dir=${conf-dir}/templates.d
preset-templates-dir=${conf-dir}/presets.d
ssl.truststore=${conf-dir}/truststore.p12
Expand Down

0 comments on commit 702a425

Please sign in to comment.