Skip to content

Commit 5b476d9

Browse files
committed
Metadata service to remove multiple legacy templates
This adds a way to be able to remove multiple legacy index templates in one cluster state update.
1 parent bf57b74 commit 5b476d9

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.common.Strings;
2929
import org.elasticsearch.common.UUIDs;
3030
import org.elasticsearch.common.ValidationException;
31+
import org.elasticsearch.common.collect.ImmutableOpenMap;
3132
import org.elasticsearch.common.compress.CompressedXContent;
3233
import org.elasticsearch.common.inject.Inject;
3334
import org.elasticsearch.common.logging.HeaderWarning;
@@ -177,6 +178,71 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
177178
);
178179
}
179180

181+
/**
182+
* Removes the provided legacy index templates if they exist. This only matches the templates using exact name, wildcards are not
183+
* supported.
184+
*
185+
* The provided templates must exist in the cluster, otherwise an {@link IndexTemplateMissingException} is reported.
186+
*/
187+
public static void removeTemplates(ClusterService clusterService, Set<String> templateNames,
188+
ActionListener<AcknowledgedResponse> listener) {
189+
clusterService.submitStateUpdateTask("remove-templates [" + String.join(",", templateNames) +
190+
"]", new ClusterStateUpdateTask(Priority.URGENT, MasterNodeRequest.DEFAULT_MASTER_NODE_TIMEOUT) {
191+
192+
@Override
193+
public ClusterState execute(ClusterState currentState) throws Exception {
194+
return innerRemoveTemplates(currentState, templateNames);
195+
}
196+
197+
@Override
198+
public void onFailure(String source, Exception e) {
199+
listener.onFailure(e);
200+
}
201+
202+
@Override
203+
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
204+
listener.onResponse(AcknowledgedResponse.TRUE);
205+
}
206+
});
207+
}
208+
209+
/**
210+
* Removes the provided legacy templates. If an index name that doesn't exist is provided, it'll fail with
211+
* {@link IndexTemplateMissingException}
212+
*/
213+
// Package visible for testing
214+
static ClusterState innerRemoveTemplates(ClusterState currentState, Set<String> templateNames) {
215+
Set<String> existingTemplatesToDelete = new HashSet<>(templateNames.size(), 1.0f);
216+
ImmutableOpenMap<String, IndexTemplateMetadata> clusterLegacyTemplates = currentState.getMetadata().templates();
217+
Set<String> missingNames = null;
218+
for (String legacyTemplate : templateNames) {
219+
if (clusterLegacyTemplates.containsKey(legacyTemplate)) {
220+
existingTemplatesToDelete.add(legacyTemplate);
221+
} else {
222+
if (missingNames == null) {
223+
missingNames = new HashSet<>();
224+
}
225+
226+
missingNames.add(legacyTemplate);
227+
}
228+
}
229+
230+
if (missingNames != null) {
231+
throw new IndexTemplateMissingException(String.join(",", missingNames));
232+
}
233+
234+
if (existingTemplatesToDelete.isEmpty() == false) {
235+
Metadata.Builder metadata = Metadata.builder(currentState.metadata());
236+
for (String template : existingTemplatesToDelete) {
237+
logger.info("removing template [{}]", template);
238+
metadata.removeTemplate(template);
239+
}
240+
return ClusterState.builder(currentState).metadata(metadata).build();
241+
} else {
242+
return currentState;
243+
}
244+
}
245+
180246
/**
181247
* Add the given component template to the cluster state. If {@code create} is true, an
182248
* exception will be thrown if the component template already exists

server/src/test/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateServiceTests.java

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,6 +2128,122 @@ public void onFailure(Exception e) {
21282128
return throwables;
21292129
}
21302130

2131+
public void testRemoveMultipleLegacyIndexTemplates() throws Exception {
2132+
MetadataIndexTemplateService metadataIndexTemplateService = getMetadataIndexTemplateService();
2133+
AtomicReference<Throwable> failure = new AtomicReference<>();
2134+
2135+
{
2136+
PutRequest request = new PutRequest("api", "foo");
2137+
request.patterns(singletonList("fo*"));
2138+
request.mappings(new CompressedXContent("{}"));
2139+
final CountDownLatch latch = new CountDownLatch(1);
2140+
metadataIndexTemplateService.putTemplate(request, new MetadataIndexTemplateService.PutListener() {
2141+
@Override
2142+
public void onResponse(MetadataIndexTemplateService.PutResponse response) {
2143+
latch.countDown();
2144+
}
2145+
2146+
@Override
2147+
public void onFailure(Exception e) {
2148+
logger.error(e.getMessage(), e);
2149+
failure.set(e);
2150+
latch.countDown();
2151+
}
2152+
});
2153+
latch.await(10, TimeUnit.SECONDS);
2154+
assertThat("Unable to put template due to: " + failure.get(), failure.get(), nullValue());
2155+
}
2156+
2157+
{
2158+
PutRequest request = new PutRequest("api", "bar");
2159+
request.patterns(singletonList("ba*"));
2160+
request.mappings(new CompressedXContent("{}"));
2161+
2162+
final CountDownLatch latch = new CountDownLatch(1);
2163+
metadataIndexTemplateService.putTemplate(request, new MetadataIndexTemplateService.PutListener() {
2164+
@Override
2165+
public void onResponse(MetadataIndexTemplateService.PutResponse response) {
2166+
latch.countDown();
2167+
}
2168+
2169+
@Override
2170+
public void onFailure(Exception e) {
2171+
logger.error(e.getMessage(), e);
2172+
failure.set(e);
2173+
latch.countDown();
2174+
}
2175+
});
2176+
latch.await(10, TimeUnit.SECONDS);
2177+
assertThat("Unable to put template due to: " + failure.get(), failure.get(), nullValue());
2178+
}
2179+
2180+
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
2181+
ClusterState nextState = MetadataIndexTemplateService.innerRemoveTemplates(clusterService.state(), Set.of("foo", "bar"));
2182+
ImmutableOpenMap<String, IndexTemplateMetadata> templates = nextState.metadata().templates();
2183+
assertThat(templates.containsKey("foo"), is(false));
2184+
assertThat(templates.containsKey("bar"), is(false));
2185+
}
2186+
2187+
public void testRemovingLegacyMissingTemplatesFails() throws Exception {
2188+
MetadataIndexTemplateService metadataIndexTemplateService = getMetadataIndexTemplateService();
2189+
AtomicReference<Throwable> failure = new AtomicReference<>();
2190+
{
2191+
PutRequest request = new PutRequest("api", "foo");
2192+
request.patterns(singletonList("fo*"));
2193+
request.mappings(new CompressedXContent("{}"));
2194+
2195+
final CountDownLatch latch = new CountDownLatch(1);
2196+
metadataIndexTemplateService.putTemplate(request, new MetadataIndexTemplateService.PutListener() {
2197+
@Override
2198+
public void onResponse(MetadataIndexTemplateService.PutResponse response) {
2199+
latch.countDown();
2200+
}
2201+
2202+
@Override
2203+
public void onFailure(Exception e) {
2204+
logger.error(e.getMessage(), e);
2205+
failure.set(e);
2206+
latch.countDown();
2207+
}
2208+
});
2209+
latch.await(10, TimeUnit.SECONDS);
2210+
assertThat("Unable to put template due to: " + failure.get(), failure.get(), nullValue());
2211+
}
2212+
2213+
{
2214+
PutRequest request = new PutRequest("api", "bar");
2215+
request.patterns(singletonList("ba*"));
2216+
request.mappings(new CompressedXContent("{}"));
2217+
final CountDownLatch latch = new CountDownLatch(1);
2218+
metadataIndexTemplateService.putTemplate(request, new MetadataIndexTemplateService.PutListener() {
2219+
@Override
2220+
public void onResponse(MetadataIndexTemplateService.PutResponse response) {
2221+
latch.countDown();
2222+
}
2223+
2224+
@Override
2225+
public void onFailure(Exception e) {
2226+
logger.error(e.getMessage(), e);
2227+
failure.set(e);
2228+
latch.countDown();
2229+
}
2230+
});
2231+
latch.await(10, TimeUnit.SECONDS);
2232+
assertThat("Unable to put template due to: " + failure.get(), failure.get(), nullValue());
2233+
}
2234+
2235+
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
2236+
IndexTemplateMissingException indexTemplateMissingException = expectThrows(IndexTemplateMissingException.class,
2237+
() -> MetadataIndexTemplateService.innerRemoveTemplates(clusterService.state(),
2238+
Set.of("foo", "bar", "missing", "other_mssing")));
2239+
assertThat(indexTemplateMissingException.getMessage(), is("index_template [missing,other_mssing] missing"));
2240+
2241+
// let's also test the templates that did exists were not removed
2242+
ImmutableOpenMap<String, IndexTemplateMetadata> templates = clusterService.state().metadata().templates();
2243+
assertThat(templates.containsKey("foo"), is(true));
2244+
assertThat(templates.containsKey("bar"), is(true));
2245+
}
2246+
21312247
private List<Throwable> putTemplateDetail(PutRequest request) throws Exception {
21322248
MetadataIndexTemplateService service = getMetadataIndexTemplateService();
21332249

0 commit comments

Comments
 (0)