Skip to content

Commit 6bab477

Browse files
committed
Filter enrich policy index deletes to just the policy's associated indices (#82568)
1 parent eebbc7b commit 6bab477

File tree

5 files changed

+114
-21
lines changed

5 files changed

+114
-21
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/enrich/EnrichPolicy.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,32 @@ public static String getBaseName(String policyName) {
169169
return ENRICH_INDEX_NAME_BASE + policyName;
170170
}
171171

172+
/**
173+
* Given a policy name and a timestamp, return the enrich index name that should be used.
174+
*
175+
* @param policyName the name of the policy
176+
* @param nowTimestamp the current time
177+
* @return an enrich index name
178+
*/
179+
public static String getIndexName(String policyName, long nowTimestamp) {
180+
Objects.nonNull(policyName);
181+
return EnrichPolicy.getBaseName(policyName) + "-" + nowTimestamp;
182+
}
183+
184+
/**
185+
* Tests whether the named policy is associated with the named index according to the naming
186+
* pattern that exists between policy names and index names.
187+
*
188+
* @param policyName the policy name
189+
* @param indexName the index name
190+
* @return true if and only if the named policy is associated with the named index
191+
*/
192+
public static boolean isPolicyForIndex(String policyName, String indexName) {
193+
Objects.nonNull(policyName);
194+
Objects.nonNull(indexName);
195+
return indexName.matches(EnrichPolicy.getBaseName(policyName) + "-" + "\\d+");
196+
}
197+
172198
@Override
173199
public void writeTo(StreamOutput out) throws IOException {
174200
out.writeString(type);

x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/EnrichPolicyRunner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ private XContentBuilder createEnrichMappingBuilder(CheckedFunction<XContentBuild
372372

373373
private void prepareAndCreateEnrichIndex(List<Map<String, Object>> mappings) {
374374
long nowTimestamp = nowSupplier.getAsLong();
375-
String enrichIndexName = EnrichPolicy.getBaseName(policyName) + "-" + nowTimestamp;
375+
String enrichIndexName = EnrichPolicy.getIndexName(policyName, nowTimestamp);
376376
Settings enrichIndexSettings = Settings.builder()
377377
.put("index.number_of_shards", 1)
378378
.put("index.number_of_replicas", 0)

x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyAction.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
import java.util.ArrayList;
3838
import java.util.List;
39+
import java.util.stream.Stream;
3940

4041
import static org.elasticsearch.xpack.core.ClientHelper.ENRICH_ORIGIN;
4142

@@ -80,23 +81,24 @@ protected void masterOperation(
8081
ClusterState state,
8182
ActionListener<AcknowledgedResponse> listener
8283
) throws Exception {
83-
EnrichPolicy policy = EnrichStore.getPolicy(request.getName(), state); // ensure the policy exists first
84+
final String policyName = request.getName();
85+
final EnrichPolicy policy = EnrichStore.getPolicy(policyName, state); // ensure the policy exists first
8486
if (policy == null) {
85-
throw new ResourceNotFoundException("policy [{}] not found", request.getName());
87+
throw new ResourceNotFoundException("policy [{}] not found", policyName);
8688
}
8789

88-
enrichPolicyLocks.lockPolicy(request.getName());
90+
enrichPolicyLocks.lockPolicy(policyName);
8991
try {
90-
List<PipelineConfiguration> pipelines = IngestService.getPipelines(state);
91-
List<String> pipelinesWithProcessors = new ArrayList<>();
92+
final List<PipelineConfiguration> pipelines = IngestService.getPipelines(state);
93+
final List<String> pipelinesWithProcessors = new ArrayList<>();
9294

9395
for (PipelineConfiguration pipelineConfiguration : pipelines) {
9496
List<AbstractEnrichProcessor> enrichProcessors = ingestService.getProcessorsInPipeline(
9597
pipelineConfiguration.getId(),
9698
AbstractEnrichProcessor.class
9799
);
98100
for (AbstractEnrichProcessor processor : enrichProcessors) {
99-
if (processor.getPolicyName().equals(request.getName())) {
101+
if (processor.getPolicyName().equals(policyName)) {
100102
pipelinesWithProcessors.add(pipelineConfiguration.getId());
101103
}
102104
}
@@ -106,26 +108,30 @@ protected void masterOperation(
106108
throw new ElasticsearchStatusException(
107109
"Could not delete policy [{}] because a pipeline is referencing it {}",
108110
RestStatus.CONFLICT,
109-
request.getName(),
111+
policyName,
110112
pipelinesWithProcessors
111113
);
112114
}
113115
} catch (Exception e) {
114-
enrichPolicyLocks.releasePolicy(request.getName());
116+
enrichPolicyLocks.releasePolicy(policyName);
115117
listener.onFailure(e);
116118
return;
117119
}
118120

119-
GetIndexRequest indices = new GetIndexRequest().indices(EnrichPolicy.getBaseName(request.getName()) + "-*")
121+
final GetIndexRequest indices = new GetIndexRequest().indices(EnrichPolicy.getBaseName(policyName) + "-*")
120122
.indicesOptions(IndicesOptions.lenientExpand());
121123

122124
String[] concreteIndices = indexNameExpressionResolver.concreteIndexNamesWithSystemIndexAccess(state, indices);
123125

124-
deleteIndicesAndPolicy(concreteIndices, request.getName(), ActionListener.wrap((response) -> {
125-
enrichPolicyLocks.releasePolicy(request.getName());
126+
// the wildcard expansion could be too wide (e.g. in the case of a policy named policy-1 and another named policy-10),
127+
// so we need to filter down to just the concrete indices that are actually indices for this policy
128+
concreteIndices = Stream.of(concreteIndices).filter(i -> EnrichPolicy.isPolicyForIndex(policyName, i)).toArray(String[]::new);
129+
130+
deleteIndicesAndPolicy(concreteIndices, policyName, ActionListener.wrap((response) -> {
131+
enrichPolicyLocks.releasePolicy(policyName);
126132
listener.onResponse(response);
127133
}, (exc) -> {
128-
enrichPolicyLocks.releasePolicy(request.getName());
134+
enrichPolicyLocks.releasePolicy(policyName);
129135
listener.onFailure(exc);
130136
}));
131137
}

x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichPolicyTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,19 @@ public static void assertEqualPolicies(EnrichPolicy expectedInstance, EnrichPoli
9797
assertThat(newInstance.getMatchField(), equalTo(expectedInstance.getMatchField()));
9898
assertThat(newInstance.getEnrichFields(), equalTo(expectedInstance.getEnrichFields()));
9999
}
100+
101+
public void testIsPolicyForIndex() {
102+
String policy1 = "policy-1";
103+
String policy2 = "policy-10"; // the first policy is a prefix of the second policy!
104+
105+
String index1 = EnrichPolicy.getIndexName(policy1, 1000);
106+
String index2 = EnrichPolicy.getIndexName(policy2, 2000);
107+
108+
assertTrue(EnrichPolicy.isPolicyForIndex(policy1, index1));
109+
assertTrue(EnrichPolicy.isPolicyForIndex(policy2, index2));
110+
111+
assertFalse(EnrichPolicy.isPolicyForIndex(policy1, index2));
112+
assertFalse(EnrichPolicy.isPolicyForIndex(policy2, index1));
113+
}
114+
100115
}

x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/TransportDeleteEnrichPolicyActionTests.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public void cleanupPolicy() {
5252

5353
public void testDeletePolicyDoesNotExistUnlocksPolicy() throws InterruptedException {
5454
String fakeId = "fake-id";
55-
createIndex(EnrichPolicy.getBaseName(fakeId) + "-foo1");
56-
createIndex(EnrichPolicy.getBaseName(fakeId) + "-foo2");
55+
createIndex(EnrichPolicy.getIndexName(fakeId, 1001));
56+
createIndex(EnrichPolicy.getIndexName(fakeId, 1002));
5757

5858
final CountDownLatch latch = new CountDownLatch(1);
5959
final AtomicReference<Exception> reference = new AtomicReference<>();
@@ -127,13 +127,13 @@ public void testDeleteIsNotLocked() throws Exception {
127127
assertAcked(client().admin().cluster().prepareUpdateSettings().setPersistentSettings(settings));
128128
}
129129

130-
createIndex(EnrichPolicy.getBaseName(name) + "-foo1");
131-
createIndex(EnrichPolicy.getBaseName(name) + "-foo2");
130+
createIndex(EnrichPolicy.getIndexName(name, 1001));
131+
createIndex(EnrichPolicy.getIndexName(name, 1002));
132132

133133
client().admin()
134134
.indices()
135135
.prepareGetIndex()
136-
.setIndices(EnrichPolicy.getBaseName(name) + "-foo1", EnrichPolicy.getBaseName(name) + "-foo2")
136+
.setIndices(EnrichPolicy.getIndexName(name, 1001), EnrichPolicy.getIndexName(name, 1002))
137137
.get();
138138

139139
final CountDownLatch latch = new CountDownLatch(1);
@@ -159,7 +159,7 @@ public void onFailure(final Exception e) {
159159
() -> client().admin()
160160
.indices()
161161
.prepareGetIndex()
162-
.setIndices(EnrichPolicy.getBaseName(name) + "-foo1", EnrichPolicy.getBaseName(name) + "-foo2")
162+
.setIndices(EnrichPolicy.getIndexName(name, 1001), EnrichPolicy.getIndexName(name, 1001))
163163
.get()
164164
);
165165

@@ -182,8 +182,8 @@ public void testDeleteLocked() throws InterruptedException {
182182
AtomicReference<Exception> error = saveEnrichPolicy(name, policy, clusterService);
183183
assertThat(error.get(), nullValue());
184184

185-
createIndex(EnrichPolicy.getBaseName(name) + "-foo1");
186-
createIndex(EnrichPolicy.getBaseName(name) + "-foo2");
185+
createIndex(EnrichPolicy.getIndexName(name, 1001));
186+
createIndex(EnrichPolicy.getIndexName(name, 1002));
187187

188188
EnrichPolicyLocks enrichPolicyLocks = getInstanceFromNode(EnrichPolicyLocks.class);
189189
assertFalse(enrichPolicyLocks.captureExecutionState().isAnyPolicyInFlight());
@@ -240,4 +240,50 @@ public void onFailure(final Exception e) {
240240
assertNull(EnrichStore.getPolicy(name, clusterService.state()));
241241
}
242242
}
243+
244+
public void testDeletePolicyPrefixes() throws InterruptedException {
245+
EnrichPolicy policy = randomEnrichPolicy(XContentType.JSON);
246+
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
247+
248+
String name = "my-policy";
249+
String otherName = "my-policy-two"; // the first policy is a prefix of this one
250+
251+
final TransportDeleteEnrichPolicyAction transportAction = node().injector().getInstance(TransportDeleteEnrichPolicyAction.class);
252+
AtomicReference<Exception> error;
253+
error = saveEnrichPolicy(name, policy, clusterService);
254+
assertThat(error.get(), nullValue());
255+
error = saveEnrichPolicy(otherName, policy, clusterService);
256+
assertThat(error.get(), nullValue());
257+
258+
// create an index for the *other* policy
259+
createIndex(EnrichPolicy.getIndexName(otherName, 1001));
260+
261+
{
262+
final CountDownLatch latch = new CountDownLatch(1);
263+
final AtomicReference<AcknowledgedResponse> reference = new AtomicReference<>();
264+
265+
transportAction.execute(null, new DeleteEnrichPolicyAction.Request(name), new ActionListener<AcknowledgedResponse>() {
266+
@Override
267+
public void onResponse(AcknowledgedResponse acknowledgedResponse) {
268+
reference.set(acknowledgedResponse);
269+
latch.countDown();
270+
}
271+
272+
public void onFailure(final Exception e) {
273+
fail();
274+
}
275+
});
276+
latch.await();
277+
assertNotNull(reference.get());
278+
assertTrue(reference.get().isAcknowledged());
279+
280+
assertNull(EnrichStore.getPolicy(name, clusterService.state()));
281+
282+
// deleting name policy should have no effect on the other policy
283+
assertNotNull(EnrichStore.getPolicy(otherName, clusterService.state()));
284+
285+
// and the index associated with the other index should be unaffected
286+
client().admin().indices().prepareGetIndex().setIndices(EnrichPolicy.getIndexName(otherName, 1001)).get();
287+
}
288+
}
243289
}

0 commit comments

Comments
 (0)