Skip to content

Commit b437f49

Browse files
committed
feat(rules): implement declarative Automated Rules
1 parent cf0af40 commit b437f49

File tree

5 files changed

+84
-0
lines changed

5 files changed

+84
-0
lines changed

src/main/docker/Dockerfile.jvm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ ENTRYPOINT [ "/deployments/app/entrypoint.bash", "/opt/jboss/container/java/run/
9393
# We make distinct layers so if there are application changes the library layers can be re-used
9494
COPY --chown=185 src/main/docker/include/cryostat.jfc /usr/lib/jvm/jre/lib/jfr/
9595
COPY --chown=185 src/main/docker/include/template_presets/* /opt/cryostat.d/presets.d/
96+
COPY --chown=185 src/main/docker/include/rule_presets/* /opt/cryostat.d/rules.d/
9697
COPY --chown=185 src/main/docker/include/genpass.bash /deployments/app/
9798
COPY --chown=185 src/main/docker/include/entrypoint.bash /deployments/app/
9899
COPY --chown=185 src/main/docker/include/truststore-setup.bash /deployments/app/
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "quarkus",
3+
"description": "Preset Automated Rule for enabling Quarkus framework-specific events when available",
4+
"eventSpecifier": "template=Quarkus,type=PRESET",
5+
"matchExpression": "jfrEventTypeIds(target).exists(x, x.contains(\"quarkus\"))",
6+
"enabled": false
7+
}

src/main/java/io/cryostat/ConfigProperties.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class ConfigProperties {
5757
public static final String CUSTOM_TEMPLATES_DIR = "templates-dir";
5858
public static final String PRESET_TEMPLATES_DIR = "preset-templates-dir";
5959
public static final String SSL_TRUSTSTORE_DIR = "ssl.truststore.dir";
60+
public static final String RULES_DIR = "rules-dir";
6061

6162
public static final String URI_RANGE = "cryostat.target.uri-range";
6263
}

src/main/java/io/cryostat/rules/Rules.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@
1515
*/
1616
package io.cryostat.rules;
1717

18+
import java.io.BufferedInputStream;
19+
import java.io.IOException;
20+
import java.nio.file.Files;
1821
import java.util.List;
22+
import java.util.Objects;
1923

24+
import io.cryostat.ConfigProperties;
2025
import io.cryostat.expressions.MatchExpression;
2126
import io.cryostat.util.EntityExistsException;
2227

28+
import com.fasterxml.jackson.databind.ObjectMapper;
29+
import io.quarkus.runtime.StartupEvent;
2330
import io.vertx.core.json.JsonObject;
2431
import io.vertx.mutiny.core.eventbus.EventBus;
2532
import jakarta.annotation.security.RolesAllowed;
33+
import jakarta.enterprise.event.Observes;
2634
import jakarta.inject.Inject;
2735
import jakarta.transaction.Transactional;
2836
import jakarta.ws.rs.BadRequestException;
@@ -36,6 +44,8 @@
3644
import jakarta.ws.rs.core.Context;
3745
import jakarta.ws.rs.core.MediaType;
3846
import jakarta.ws.rs.core.UriInfo;
47+
import org.eclipse.microprofile.config.inject.ConfigProperty;
48+
import org.jboss.logging.Logger;
3949
import org.jboss.resteasy.reactive.RestForm;
4050
import org.jboss.resteasy.reactive.RestPath;
4151
import org.jboss.resteasy.reactive.RestQuery;
@@ -45,7 +55,71 @@
4555
@Path("/api/v4/rules")
4656
public class Rules {
4757

58+
@ConfigProperty(name = ConfigProperties.RULES_DIR)
59+
java.nio.file.Path dir;
60+
61+
@Inject Logger logger;
4862
@Inject EventBus bus;
63+
@Inject ObjectMapper mapper;
64+
65+
@Transactional
66+
void onStart(@Observes StartupEvent evt) {
67+
if (!checkDir()) {
68+
return;
69+
}
70+
try {
71+
Files.walk(dir)
72+
.filter(Files::isRegularFile)
73+
.filter(Files::isReadable)
74+
.peek(
75+
p ->
76+
logger.tracev(
77+
"Processing declarative Automated Rule definition at"
78+
+ " {}",
79+
p))
80+
.forEach(this::processDeclarativeRule);
81+
} catch (IOException e) {
82+
logger.error(e);
83+
}
84+
}
85+
86+
private void processDeclarativeRule(java.nio.file.Path path) {
87+
try (var is = new BufferedInputStream(Files.newInputStream(path))) {
88+
var declarativeRule = mapper.readValue(is, Rule.class);
89+
logger.tracev(
90+
"Processing eclarative Automated" + " Rule with name \"{}\"",
91+
declarativeRule.name);
92+
var exists = Rule.find("name", declarativeRule.name).count() != 0;
93+
if (exists) {
94+
var existingRule = Rule.<Rule>find("name", declarativeRule.name).singleResult();
95+
// remove for equality check. The declarative rule is not expected to have a
96+
// database ID yet existingRule.id = null;
97+
if (Objects.equals(declarativeRule, existingRule)) {
98+
return;
99+
}
100+
logger.debugv(
101+
"Rule with name \"{}\" already exists in database. Replacing with"
102+
+ " declarative rule at {}. Previous definition:\n"
103+
+ "{}",
104+
declarativeRule.name,
105+
path,
106+
mapper.writeValueAsString(existingRule));
107+
existingRule.delete();
108+
}
109+
declarativeRule.persist();
110+
} catch (IOException ioe) {
111+
logger.warn(ioe);
112+
} catch (Exception e) {
113+
logger.error(e);
114+
}
115+
}
116+
117+
private boolean checkDir() {
118+
return Files.exists(dir)
119+
&& Files.isReadable(dir)
120+
&& Files.isExecutable(dir)
121+
&& Files.isDirectory(dir);
122+
}
49123

50124
@GET
51125
@RolesAllowed("read")

src/main/resources/application.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ cryostat.http.proxy.path=/
4747
cryostat.target.uri-range=PUBLIC
4848

4949
conf-dir=/opt/cryostat.d
50+
rules-dir=${conf-dir}/rules.d
5051
templates-dir=${conf-dir}/templates.d
5152
preset-templates-dir=${conf-dir}/presets.d
5253
ssl.truststore=${conf-dir}/truststore.p12

0 commit comments

Comments
 (0)