Skip to content

Commit 76e35a9

Browse files
authored
Backport 6.2: Fix rule fragment loading in rule builder (#22645) (#22674)
* Fix rule fragment loading in rule builder (#22645) * update rule fragments in RuleBuilderRegistry on cluster event when they are changed via the service, cache these and reload only on change * cl * rename local freemarker configuration variable * move event bus post after db action (cherry picked from commit defe540) * add backport pr to changelog
1 parent 50687d1 commit 76e35a9

File tree

9 files changed

+96
-40
lines changed

9 files changed

+96
-40
lines changed

changelog/unreleased/pr-22645.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type = "f"
2+
message = "Fixed using certain conditions and actions in the rule builder after inital setup of Graylog without restart."
3+
4+
issues = ["20793"]
5+
pulls = ["22645", "22674"]

graylog2-server/src/main/java/org/graylog/plugins/pipelineprocessor/rulebuilder/RuleBuilderRegistry.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@
1717
package org.graylog.plugins.pipelineprocessor.rulebuilder;
1818

1919
import com.google.common.collect.Streams;
20+
import com.google.common.eventbus.EventBus;
21+
import com.google.common.eventbus.Subscribe;
22+
import freemarker.cache.StringTemplateLoader;
23+
import freemarker.template.Configuration;
2024
import jakarta.inject.Inject;
2125
import org.graylog.plugins.pipelineprocessor.ast.functions.Function;
2226
import org.graylog.plugins.pipelineprocessor.parser.FunctionRegistry;
2327
import org.graylog.plugins.pipelineprocessor.rulebuilder.db.RuleFragment;
2428
import org.graylog.plugins.pipelineprocessor.rulebuilder.db.RuleFragmentService;
29+
import org.graylog2.bindings.providers.SecureFreemarkerConfigProvider;
2530

2631
import java.util.Collection;
2732
import java.util.Map;
@@ -32,12 +37,21 @@ public class RuleBuilderRegistry {
3237

3338
private final FunctionRegistry functionRegistry;
3439
private final RuleFragmentService ruleFragmentService;
40+
private final SecureFreemarkerConfigProvider secureFreemarkerConfigProvider;
41+
private Collection<RuleFragment> ruleFragments;
42+
private Configuration freemarkerConfiguration;
3543

3644
@Inject
3745
public RuleBuilderRegistry(FunctionRegistry functionRegistry,
38-
RuleFragmentService ruleFragmentService) {
46+
RuleFragmentService ruleFragmentService,
47+
SecureFreemarkerConfigProvider secureFreemarkerConfigProvider,
48+
EventBus eventBus) {
3949
this.functionRegistry = functionRegistry;
4050
this.ruleFragmentService = ruleFragmentService;
51+
this.ruleFragments = ruleFragmentService.all();
52+
this.secureFreemarkerConfigProvider = secureFreemarkerConfigProvider;
53+
initializeFragmentTemplates();
54+
eventBus.register(this);
4155
}
4256

4357
/**
@@ -68,7 +82,7 @@ private Map<String, RuleFragment> collectConditions(Collection<Function<?>> func
6882
.descriptor(f.descriptor())
6983
.build()
7084
);
71-
final Stream<RuleFragment> fragmentConditions = ruleFragmentService.all().stream()
85+
final Stream<RuleFragment> fragmentConditions = ruleFragments.stream()
7286
.filter(f -> f.descriptor().ruleBuilderEnabled() && f.isCondition());
7387
return Streams.concat(functionConditions, fragmentConditions)
7488
.collect(Collectors.toMap(f -> f.descriptor().name(), function -> function));
@@ -103,10 +117,30 @@ public Map<String, RuleFragment> collectActions(Collection<Function<?>> function
103117
.build()
104118
);
105119
final Stream<RuleFragment> fragmentActions =
106-
ruleFragmentService.all().stream()
120+
ruleFragments.stream()
107121
.filter(f -> f.descriptor().ruleBuilderEnabled() && !f.isCondition());
108122
return Streams.concat(functionActions, fragmentActions)
109123
.collect(Collectors.toMap(f -> f.descriptor().name(), function -> function));
110124
}
111125

126+
public Configuration getFreemarkerConfiguration() {
127+
return freemarkerConfiguration;
128+
}
129+
130+
private void initializeFragmentTemplates() {
131+
Map<String, RuleFragment> fragments = conditionsWithInternal();
132+
fragments.putAll(actionsWithInternal());
133+
final Configuration config = secureFreemarkerConfigProvider.get();
134+
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
135+
fragments.entrySet().stream().filter(c -> c.getValue().isFragment()).forEach(c -> stringTemplateLoader.putTemplate(c.getKey(), c.getValue().fragment()));
136+
config.setTemplateLoader(stringTemplateLoader);
137+
this.freemarkerConfiguration = config;
138+
}
139+
140+
@Subscribe
141+
public void updateRuleFragments(final RuleFragmentUpdateEvent event) {
142+
this.ruleFragments = ruleFragmentService.all();
143+
initializeFragmentTemplates();
144+
}
145+
112146
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (C) 2020 Graylog, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the Server Side Public License, version 1,
6+
* as published by MongoDB, Inc.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* Server Side Public License for more details.
12+
*
13+
* You should have received a copy of the Server Side Public License
14+
* along with this program. If not, see
15+
* <http://www.mongodb.com/licensing/server-side-public-license>.
16+
*/
17+
18+
package org.graylog.plugins.pipelineprocessor.rulebuilder;
19+
20+
public record RuleFragmentUpdateEvent() {
21+
}

graylog2-server/src/main/java/org/graylog/plugins/pipelineprocessor/rulebuilder/db/MongoDBRuleFragmentService.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
import com.mongodb.client.model.Sorts;
2525
import jakarta.inject.Inject;
2626
import jakarta.inject.Singleton;
27+
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleFragmentUpdateEvent;
2728
import org.graylog2.database.MongoCollections;
2829
import org.graylog2.database.utils.MongoUtils;
30+
import org.graylog2.events.ClusterEventBus;
2931

3032
import java.util.Collection;
3133
import java.util.Optional;
@@ -38,27 +40,33 @@ public class MongoDBRuleFragmentService implements RuleFragmentService {
3840

3941
private final MongoCollection<RuleFragment> collection;
4042
private final MongoUtils<RuleFragment> mongoUtils;
43+
private final ClusterEventBus clusterEventBus;
4144

4245
@Inject
43-
public MongoDBRuleFragmentService(MongoCollections mongoCollections) {
46+
public MongoDBRuleFragmentService(MongoCollections mongoCollections, ClusterEventBus clusterEventBus) {
4447
collection = mongoCollections.collection(COLLECTION_NAME, RuleFragment.class);
4548
mongoUtils = mongoCollections.utils(collection);
4649
collection.createIndex(Indexes.ascending("name"), new IndexOptions().unique(true));
50+
this.clusterEventBus = clusterEventBus;
4751
}
4852

4953
@Override
5054
public RuleFragment save(RuleFragment ruleFragment) {
51-
return mongoUtils.save(ruleFragment);
55+
RuleFragment fragment = mongoUtils.save(ruleFragment);
56+
clusterEventBus.post(new RuleFragmentUpdateEvent());
57+
return fragment;
5258
}
5359

5460
@Override
5561
public void delete(String name) {
5662
collection.deleteOne(eq("name", name));
63+
clusterEventBus.post(new RuleFragmentUpdateEvent());
5764
}
5865

5966
@Override
6067
public void deleteAll() {
6168
collection.deleteMany(Filters.empty());
69+
clusterEventBus.post(new RuleFragmentUpdateEvent());
6270
}
6371

6472
@Override

graylog2-server/src/main/java/org/graylog/plugins/pipelineprocessor/rulebuilder/parser/ActionParser.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616
*/
1717
package org.graylog.plugins.pipelineprocessor.rulebuilder.parser;
1818

19-
import freemarker.template.Configuration;
2019
import jakarta.inject.Inject;
2120
import jakarta.inject.Singleton;
2221
import org.graylog.plugins.pipelineprocessor.ast.functions.FunctionDescriptor;
2322
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderRegistry;
2423
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderStep;
2524
import org.graylog.plugins.pipelineprocessor.rulebuilder.db.RuleFragment;
26-
import org.graylog2.bindings.providers.SecureFreemarkerConfigProvider;
2725

2826
import java.util.List;
2927
import java.util.Map;
@@ -35,18 +33,16 @@
3533
public class ActionParser {
3634

3735
public static final String NL = System.lineSeparator();
38-
protected final Map<String, RuleFragment> actions;
3936

40-
private final Configuration freemarkerConfiguration;
37+
private final RuleBuilderRegistry ruleBuilderRegistry;
4138

4239
@Inject
43-
public ActionParser(RuleBuilderRegistry ruleBuilderRegistry, SecureFreemarkerConfigProvider secureFreemarkerConfigProvider) {
44-
this.actions = ruleBuilderRegistry.actionsWithInternal();
45-
this.freemarkerConfiguration = ParserUtil.initializeFragmentTemplates(secureFreemarkerConfigProvider, actions);
40+
public ActionParser(RuleBuilderRegistry ruleBuilderRegistry) {
41+
this.ruleBuilderRegistry = ruleBuilderRegistry;
4642
}
4743

4844
public Map<String, RuleFragment> getActions() {
49-
return actions;
45+
return ruleBuilderRegistry.actionsWithInternal();
5046
}
5147

5248
public String generate(List<RuleBuilderStep> actions, boolean generateSimulatorFields) {
@@ -55,7 +51,7 @@ public String generate(List<RuleBuilderStep> actions, boolean generateSimulatorF
5551
}
5652

5753
String generateAction(RuleBuilderStep step, boolean generateSimulatorFields, int index) {
58-
final RuleFragment ruleFragment = actions.get(step.function());
54+
final RuleFragment ruleFragment = getActions().get(step.function());
5955
if (Objects.isNull(ruleFragment)) {
6056
return "";
6157
}
@@ -72,7 +68,7 @@ String generateAction(RuleBuilderStep step, boolean generateSimulatorFields, int
7268
}
7369

7470
if (ruleFragment.isFragment()) {
75-
syntax += ParserUtil.generateForFragment(step, freemarkerConfiguration);
71+
syntax += ParserUtil.generateForFragment(step, ruleBuilderRegistry.getFreemarkerConfiguration());
7672
} else {
7773
syntax += ParserUtil.generateForFunction(step, function) + ";";
7874
}

graylog2-server/src/main/java/org/graylog/plugins/pipelineprocessor/rulebuilder/parser/ConditionParser.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@
1616
*/
1717
package org.graylog.plugins.pipelineprocessor.rulebuilder.parser;
1818

19-
import freemarker.template.Configuration;
2019
import jakarta.inject.Inject;
2120
import jakarta.inject.Singleton;
2221
import org.apache.commons.lang3.StringUtils;
2322
import org.graylog.plugins.pipelineprocessor.ast.functions.FunctionDescriptor;
2423
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderRegistry;
2524
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderStep;
2625
import org.graylog.plugins.pipelineprocessor.rulebuilder.db.RuleFragment;
27-
import org.graylog2.bindings.providers.SecureFreemarkerConfigProvider;
2826

2927
import java.util.List;
3028
import java.util.Map;
@@ -37,18 +35,16 @@ public class ConditionParser {
3735

3836
public static final String NL = System.lineSeparator();
3937
private static final String INDENT = " ";
40-
protected final Map<String, RuleFragment> conditions;
4138

42-
private final Configuration freemarkerConfiguration;
39+
private final RuleBuilderRegistry ruleBuilderRegistry;
4340

4441
@Inject
45-
public ConditionParser(RuleBuilderRegistry ruleBuilderRegistry, SecureFreemarkerConfigProvider secureFreemarkerConfigProvider) {
46-
this.conditions = ruleBuilderRegistry.conditionsWithInternal();
47-
freemarkerConfiguration = ParserUtil.initializeFragmentTemplates(secureFreemarkerConfigProvider, conditions);
42+
public ConditionParser(RuleBuilderRegistry ruleBuilderRegistry) {
43+
this.ruleBuilderRegistry = ruleBuilderRegistry;
4844
}
4945

5046
public Map<String, RuleFragment> getConditions() {
51-
return conditions;
47+
return ruleBuilderRegistry.conditions();
5248
}
5349

5450
public String generate(List<RuleBuilderStep> ruleConditions, RuleBuilderStep.Operator operator, int level) {
@@ -90,14 +86,14 @@ String generateCondition(RuleBuilderStep step, int level) {
9086
syntax += "! ";
9187
}
9288

93-
final RuleFragment ruleFragment = conditions.get(step.function());
89+
final RuleFragment ruleFragment = getConditions().get(step.function());
9490
if (Objects.isNull(ruleFragment)) {
9591
return "";
9692
}
9793
FunctionDescriptor<?> function = ruleFragment.descriptor();
9894

9995
if (ruleFragment.isFragment()) {
100-
syntax += ParserUtil.generateForFragment(step, freemarkerConfiguration);
96+
syntax += ParserUtil.generateForFragment(step, ruleBuilderRegistry.getFreemarkerConfiguration());
10197
} else {
10298
syntax += ParserUtil.generateForFunction(step, function, level);
10399
}
@@ -116,4 +112,5 @@ private String generateConditionVariable(int index, RuleBuilderStep step) {
116112
String fieldname = (step.outputvariable() == null) ? Integer.toString(index) : step.outputvariable();
117113
return "set_field(\"gl2_simulator_condition_" + fieldname + "\", " + condition + ");";
118114
}
115+
119116
}

graylog2-server/src/main/java/org/graylog/plugins/pipelineprocessor/rulebuilder/parser/ParserUtil.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
package org.graylog.plugins.pipelineprocessor.rulebuilder.parser;
1818

19-
import freemarker.cache.StringTemplateLoader;
2019
import freemarker.template.Configuration;
2120
import freemarker.template.Template;
2221
import freemarker.template.TemplateNotFoundException;
@@ -25,8 +24,6 @@
2524
import org.graylog.plugins.pipelineprocessor.ast.functions.FunctionDescriptor;
2625
import org.graylog.plugins.pipelineprocessor.ast.functions.ParameterDescriptor;
2726
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderStep;
28-
import org.graylog.plugins.pipelineprocessor.rulebuilder.db.RuleFragment;
29-
import org.graylog2.bindings.providers.SecureFreemarkerConfigProvider;
3027

3128
import java.io.StringWriter;
3229
import java.util.HashMap;
@@ -80,14 +77,6 @@ static final String addFunctionParameter(ParameterDescriptor descriptor, RuleBui
8077
return syntax;
8178
}
8279

83-
static final Configuration initializeFragmentTemplates(SecureFreemarkerConfigProvider secureFreemarkerConfigProvider, Map<String, RuleFragment> fragments) {
84-
final Configuration freemarkerConfiguration = secureFreemarkerConfigProvider.get();
85-
StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
86-
fragments.entrySet().stream().filter(c -> c.getValue().isFragment()).forEach(c -> stringTemplateLoader.putTemplate(c.getKey(), c.getValue().fragment()));
87-
freemarkerConfiguration.setTemplateLoader(stringTemplateLoader);
88-
return freemarkerConfiguration;
89-
}
90-
9180
static final String generateForFragment(RuleBuilderStep step, Configuration configuration) {
9281
final String fragmentName = step.function();
9382
try {

graylog2-server/src/test/java/org/graylog/plugins/pipelineprocessor/rulebuilder/parser/ActionParserTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.google.common.collect.ImmutableList;
2020
import com.google.common.collect.Maps;
21+
import com.google.common.eventbus.EventBus;
2122
import org.graylog.plugins.pipelineprocessor.ast.functions.Function;
2223
import org.graylog.plugins.pipelineprocessor.parser.FunctionRegistry;
2324
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderRegistry;
@@ -73,16 +74,18 @@ public static void registerFunctions() {
7374
RuleFragmentService ruleFragmentService = mock(RuleFragmentService.class);
7475
when(ruleFragmentService.all()).thenReturn(new ArrayList<>());
7576

77+
final SecureFreemarkerConfigProvider secureFreemarkerConfigProvider = new SecureFreemarkerConfigProvider();
78+
secureFreemarkerConfigProvider.get().setLogTemplateExceptions(false);
7679
ruleBuilderRegistry = new RuleBuilderRegistry(
7780
new FunctionRegistry(functions),
78-
ruleFragmentService);
81+
ruleFragmentService, secureFreemarkerConfigProvider, new EventBus());
7982
}
8083

8184
@Before
8285
public void initialize() {
8386
final SecureFreemarkerConfigProvider secureFreemarkerConfigProvider = new SecureFreemarkerConfigProvider();
8487
secureFreemarkerConfigProvider.get().setLogTemplateExceptions(false);
85-
actionParser = new ActionParser(ruleBuilderRegistry, secureFreemarkerConfigProvider);
88+
actionParser = new ActionParser(ruleBuilderRegistry);
8689
}
8790

8891

graylog2-server/src/test/java/org/graylog/plugins/pipelineprocessor/rulebuilder/parser/ConditionParserTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import com.google.common.collect.ImmutableList;
2020
import com.google.common.collect.Maps;
21+
import com.google.common.eventbus.EventBus;
2122
import org.graylog.plugins.pipelineprocessor.ast.functions.Function;
2223
import org.graylog.plugins.pipelineprocessor.parser.FunctionRegistry;
2324
import org.graylog.plugins.pipelineprocessor.rulebuilder.RuleBuilderRegistry;
@@ -68,15 +69,17 @@ public static void registerFunctions() {
6869
RuleFragmentService ruleFragmentService = mock(RuleFragmentService.class);
6970
when(ruleFragmentService.all()).thenReturn(new ArrayList<>());
7071

72+
final SecureFreemarkerConfigProvider secureFreemarkerConfigProvider = new SecureFreemarkerConfigProvider();
73+
secureFreemarkerConfigProvider.get().setLogTemplateExceptions(false);
7174
ruleBuilderRegistry = new RuleBuilderRegistry(new FunctionRegistry(functions),
72-
ruleFragmentService);
75+
ruleFragmentService, secureFreemarkerConfigProvider, mock(EventBus.class));
7376
}
7477

7578
@Before
7679
public void initialize() {
7780
final SecureFreemarkerConfigProvider secureFreemarkerConfigProvider = new SecureFreemarkerConfigProvider();
7881
secureFreemarkerConfigProvider.get().setLogTemplateExceptions(false);
79-
conditionParser = new ConditionParser(ruleBuilderRegistry, secureFreemarkerConfigProvider);
82+
conditionParser = new ConditionParser(ruleBuilderRegistry);
8083
}
8184

8285

0 commit comments

Comments
 (0)