From 00e91c1362a5c02384ba9145ad02d9289ba5e686 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Thu, 13 Jun 2019 09:19:48 +0200 Subject: [PATCH] SONAR-12187 make ES indices read-write at startup if are read-only --- .../org/sonar/server/es/IndexCreator.java | 30 ++++++++++++ .../org/sonar/server/es/IndexCreatorTest.java | 48 ++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java b/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java index 4bee944bbfa..0a45e823dbe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/es/IndexCreator.java @@ -26,6 +26,8 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; +import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.settings.Settings; @@ -81,6 +83,8 @@ public class IndexCreator implements Startable { metadataIndexDefinition.define(context); NewIndex index = context.getIndices().values().iterator().next(); createIndex(index.build(), false); + } else { + ensureWritable(metadataMainType); } checkDbCompatibility(definitions.getIndices().values()); @@ -94,10 +98,36 @@ public class IndexCreator implements Startable { createIndex(index, true); } else if (hasDefinitionChange(index)) { updateIndex(index); + } else { + ensureWritable(index.getMainType()); } }); } + private void ensureWritable(IndexType.IndexMainType mainType) { + if (isReadOnly(mainType)) { + removeReadOnly(mainType); + } + } + + private boolean isReadOnly(IndexType.IndexMainType mainType) { + String indexName = mainType.getIndex().getName(); + String readOnly = client.nativeClient().admin().indices().getSettings(new GetSettingsRequest().indices(indexName)).actionGet() + .getSetting(indexName, "index.blocks.read_only_allow_delete"); + return readOnly != null && "true".equalsIgnoreCase(readOnly); + } + + private void removeReadOnly(IndexType.IndexMainType mainType) { + LOGGER.info("Index [{}] is read-only. Making it writable...", mainType.getIndex().getName()); + + String indexName = mainType.getIndex().getName(); + Settings.Builder builder = Settings.builder(); + builder.putNull("index.blocks.read_only_allow_delete"); + client.nativeClient().admin().indices() + .updateSettings(new UpdateSettingsRequest().indices(indexName).settings(builder.build())) + .actionGet(); + } + @Override public void stop() { // nothing to do diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java index d3d6797a4d3..b2b26d951a7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/es/IndexCreatorTest.java @@ -24,9 +24,12 @@ import com.google.common.collect.Sets; import java.util.Map; import java.util.function.Consumer; import javax.annotation.CheckForNull; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; +import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.cluster.metadata.MappingMetaData; import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.common.settings.Settings; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -174,6 +177,49 @@ public class IndexCreatorTest { .contains("Create type metadatas/metadata"); } + @Test + public void start_makes_metadata_index_read_write_if_read_only() { + run(new FakeIndexDefinition()); + + IndexMainType mainType = MetadataIndexDefinition.TYPE_METADATA; + makeReadOnly(mainType); + + run(new FakeIndexDefinition()); + + assertThat(isNotReadOnly(mainType)).isTrue(); + } + + @Test + public void start_makes_index_read_write_if_read_only() { + FakeIndexDefinition fakeIndexDefinition = new FakeIndexDefinition(); + IndexMainType fakeIndexMainType= FakeIndexDefinition.INDEX_TYPE.getMainType(); + run(fakeIndexDefinition); + + IndexMainType mainType = MetadataIndexDefinition.TYPE_METADATA; + makeReadOnly(mainType); + makeReadOnly(fakeIndexMainType); + + run(fakeIndexDefinition); + + assertThat(isNotReadOnly(mainType)).isTrue(); + assertThat(isNotReadOnly(fakeIndexMainType)).isTrue(); + } + + private boolean isNotReadOnly(IndexMainType mainType) { + String indexName = mainType.getIndex().getName(); + String readOnly = es.client().nativeClient().admin().indices().getSettings(new GetSettingsRequest().indices(indexName)).actionGet() + .getSetting(indexName, "index.blocks.read_only_allow_delete"); + return readOnly == null; + } + + private void makeReadOnly(IndexMainType mainType) { + Settings.Builder builder = Settings.builder(); + builder.put("index.blocks.read_only_allow_delete", "true"); + es.client().nativeClient().admin().indices() + .updateSettings(new UpdateSettingsRequest().indices(mainType.getIndex().getName()).settings(builder.build())) + .actionGet(); + } + private void enableBlueGreenDeployment() { settings.setProperty("sonar.blueGreenEnabled", "true"); } @@ -237,7 +283,7 @@ public class IndexCreatorTest { } private static class FakeIndexDefinition implements IndexDefinition { - private static final IndexMainType INDEX_TYPE = main(Index.simple("fakes"), "fake"); + static final IndexMainType INDEX_TYPE = main(Index.simple("fakes"), "fake"); @Override public void define(IndexDefinitionContext context) { -- 2.39.5