During a rolling upgrade it is possible that a worker node will be upgraded before the master in which case the DFA templates will not have been installed. Before a DFA task starts check that the latest template is installed and install it if necessary.
This commit is contained in:
parent
d59343b4ba
commit
d268540f20
|
@ -18,6 +18,7 @@ import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
||||||
|
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
|
@ -26,6 +27,9 @@ import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.xpack.core.template.IndexTemplateConfig;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -228,4 +232,52 @@ public final class MlIndexAndAlias {
|
||||||
listener::onFailure),
|
listener::onFailure),
|
||||||
client.admin().indices()::aliases);
|
client.admin().indices()::aliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the index template specified by {@code templateConfig} if it is not in already
|
||||||
|
* installed in {@code clusterState}.
|
||||||
|
*
|
||||||
|
* The check for presence is simple and will return the listener on
|
||||||
|
* the calling thread if successful. If the template has to be installed
|
||||||
|
* an async call will be made.
|
||||||
|
*
|
||||||
|
* @param clusterState The cluster state
|
||||||
|
* @param client For putting the template
|
||||||
|
* @param templateConfig The config
|
||||||
|
* @param listener Async listener
|
||||||
|
*/
|
||||||
|
public static void installIndexTemplateIfRequired(
|
||||||
|
ClusterState clusterState,
|
||||||
|
Client client,
|
||||||
|
IndexTemplateConfig templateConfig,
|
||||||
|
ActionListener<Boolean> listener
|
||||||
|
) {
|
||||||
|
String templateName = templateConfig.getTemplateName();
|
||||||
|
|
||||||
|
// The check for existence of the template is against the cluster state, so very cheap
|
||||||
|
if (hasIndexTemplate(clusterState, templateName)) {
|
||||||
|
listener.onResponse(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PutIndexTemplateRequest request = new PutIndexTemplateRequest(templateName)
|
||||||
|
.source(templateConfig.loadBytes(), XContentType.JSON);
|
||||||
|
request.masterNodeTimeout(TimeValue.timeValueMinutes(1));
|
||||||
|
|
||||||
|
ActionListener<AcknowledgedResponse> innerListener = ActionListener.wrap(
|
||||||
|
response -> {
|
||||||
|
if (response.isAcknowledged() == false) {
|
||||||
|
logger.warn("error adding legacy template [{}], request was not acknowledged", templateName);
|
||||||
|
}
|
||||||
|
listener.onResponse(response.isAcknowledged());
|
||||||
|
},
|
||||||
|
listener::onFailure);
|
||||||
|
|
||||||
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), ML_ORIGIN, request, innerListener,
|
||||||
|
client.admin().indices()::putTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasIndexTemplate(ClusterState state, String templateName) {
|
||||||
|
return state.getMetadata().getTemplates().containsKey(templateName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.metadata.AliasMetadata;
|
import org.elasticsearch.cluster.metadata.AliasMetadata;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
import org.elasticsearch.cluster.metadata.IndexMetadata;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexTemplateMetadata;
|
||||||
import org.elasticsearch.cluster.metadata.Metadata;
|
import org.elasticsearch.cluster.metadata.Metadata;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||||
|
@ -37,6 +38,8 @@ import org.elasticsearch.common.transport.TransportAddress;
|
||||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
import org.elasticsearch.xpack.core.ml.inference.persistence.InferenceIndexConstants;
|
||||||
|
import org.elasticsearch.xpack.core.template.IndexTemplateConfig;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
@ -93,6 +96,7 @@ public class MlIndexAndAliasTests extends ESTestCase {
|
||||||
doAnswer(withResponse(new CreateIndexResponse(true, true, FIRST_CONCRETE_INDEX))).when(indicesAdminClient).create(any(), any());
|
doAnswer(withResponse(new CreateIndexResponse(true, true, FIRST_CONCRETE_INDEX))).when(indicesAdminClient).create(any(), any());
|
||||||
when(indicesAdminClient.prepareAliases()).thenReturn(new IndicesAliasesRequestBuilder(client, IndicesAliasesAction.INSTANCE));
|
when(indicesAdminClient.prepareAliases()).thenReturn(new IndicesAliasesRequestBuilder(client, IndicesAliasesAction.INSTANCE));
|
||||||
doAnswer(withResponse(new AcknowledgedResponse(true))).when(indicesAdminClient).aliases(any(), any());
|
doAnswer(withResponse(new AcknowledgedResponse(true))).when(indicesAdminClient).aliases(any(), any());
|
||||||
|
doAnswer(withResponse(new AcknowledgedResponse(true))).when(indicesAdminClient).putTemplate(any(), any());
|
||||||
|
|
||||||
clusterAdminClient = mock(ClusterAdminClient.class);
|
clusterAdminClient = mock(ClusterAdminClient.class);
|
||||||
doAnswer(invocationOnMock -> {
|
doAnswer(invocationOnMock -> {
|
||||||
|
@ -121,6 +125,34 @@ public class MlIndexAndAliasTests extends ESTestCase {
|
||||||
verifyNoMoreInteractions(indicesAdminClient, listener);
|
verifyNoMoreInteractions(indicesAdminClient, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInstallIndexTemplateIfRequired_GivenTemplateExists() {
|
||||||
|
ClusterState clusterState = createClusterState(Collections.emptyMap(),
|
||||||
|
Collections.singletonMap(InferenceIndexConstants.LATEST_INDEX_NAME,
|
||||||
|
createIndexTemplateMetaData(InferenceIndexConstants.LATEST_INDEX_NAME,
|
||||||
|
Collections.singletonList(InferenceIndexConstants.LATEST_INDEX_NAME))));
|
||||||
|
|
||||||
|
IndexTemplateConfig inferenceTemplate = new IndexTemplateConfig(InferenceIndexConstants.LATEST_INDEX_NAME,
|
||||||
|
"not_a_real_file.json", Version.CURRENT.id, "xpack.ml.version",
|
||||||
|
Collections.singletonMap("xpack.ml.version.id", String.valueOf(Version.CURRENT.id)));
|
||||||
|
|
||||||
|
MlIndexAndAlias.installIndexTemplateIfRequired(clusterState, client, inferenceTemplate, listener);
|
||||||
|
verify(listener).onResponse(true);
|
||||||
|
verifyNoMoreInteractions(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInstallIndexTemplateIfRequired() {
|
||||||
|
ClusterState clusterState = createClusterState(Collections.emptyMap());
|
||||||
|
|
||||||
|
IndexTemplateConfig inferenceTemplate = new IndexTemplateConfig(InferenceIndexConstants.LATEST_INDEX_NAME,
|
||||||
|
"/org/elasticsearch/xpack/core/ml/inference_index_template.json", Version.CURRENT.id, "xpack.ml.version",
|
||||||
|
Collections.singletonMap("xpack.ml.version.id", String.valueOf(Version.CURRENT.id)));
|
||||||
|
|
||||||
|
MlIndexAndAlias.installIndexTemplateIfRequired(clusterState, client, inferenceTemplate, listener);
|
||||||
|
InOrder inOrder = inOrder(indicesAdminClient, listener);
|
||||||
|
inOrder.verify(indicesAdminClient).putTemplate(any(), any());
|
||||||
|
inOrder.verify(listener).onResponse(true);
|
||||||
|
}
|
||||||
|
|
||||||
public void testCreateStateIndexAndAliasIfNecessary_CleanState() {
|
public void testCreateStateIndexAndAliasIfNecessary_CleanState() {
|
||||||
ClusterState clusterState = createClusterState(Collections.emptyMap());
|
ClusterState clusterState = createClusterState(Collections.emptyMap());
|
||||||
createIndexAndAliasIfNecessary(clusterState);
|
createIndexAndAliasIfNecessary(clusterState);
|
||||||
|
@ -266,9 +298,15 @@ public class MlIndexAndAliasTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ClusterState createClusterState(Map<String, IndexMetadata> indices) {
|
private static ClusterState createClusterState(Map<String, IndexMetadata> indices) {
|
||||||
|
return createClusterState(indices, Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClusterState createClusterState(Map<String, IndexMetadata> indices, Map<String, IndexTemplateMetadata> templates) {
|
||||||
return ClusterState.builder(ClusterName.DEFAULT)
|
return ClusterState.builder(ClusterName.DEFAULT)
|
||||||
.metadata(Metadata.builder()
|
.metadata(Metadata.builder()
|
||||||
.indices(ImmutableOpenMap.<String, IndexMetadata>builder().putAll(indices).build()).build())
|
.indices(ImmutableOpenMap.<String, IndexMetadata>builder().putAll(indices).build())
|
||||||
|
.templates(ImmutableOpenMap.<String, IndexTemplateMetadata>builder().putAll(templates).build())
|
||||||
|
.build())
|
||||||
.nodes(DiscoveryNodes.builder()
|
.nodes(DiscoveryNodes.builder()
|
||||||
.add(new DiscoveryNode("", new TransportAddress(InetAddress.getLoopbackAddress(), 9200), HIDDEN_INTRODUCED_VERSION)))
|
.add(new DiscoveryNode("", new TransportAddress(InetAddress.getLoopbackAddress(), 9200), HIDDEN_INTRODUCED_VERSION)))
|
||||||
.build();
|
.build();
|
||||||
|
@ -282,6 +320,10 @@ public class MlIndexAndAliasTests extends ESTestCase {
|
||||||
return createIndexMetadata(indexName, true);
|
return createIndexMetadata(indexName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IndexTemplateMetadata createIndexTemplateMetaData(String templateName, List<String> patterns) {
|
||||||
|
return IndexTemplateMetadata.builder(templateName).patterns(patterns).build();
|
||||||
|
}
|
||||||
|
|
||||||
private static IndexMetadata createIndexMetadata(String indexName, boolean withAlias) {
|
private static IndexMetadata createIndexMetadata(String indexName, boolean withAlias) {
|
||||||
Settings settings =
|
Settings settings =
|
||||||
Settings.builder()
|
Settings.builder()
|
||||||
|
|
|
@ -773,7 +773,8 @@ public class MachineLearning extends Plugin implements SystemIndexPlugin,
|
||||||
memoryTracker.get(), client, expressionResolver),
|
memoryTracker.get(), client, expressionResolver),
|
||||||
new TransportStartDatafeedAction.StartDatafeedPersistentTasksExecutor(datafeedManager.get(), expressionResolver),
|
new TransportStartDatafeedAction.StartDatafeedPersistentTasksExecutor(datafeedManager.get(), expressionResolver),
|
||||||
new TransportStartDataFrameAnalyticsAction.TaskExecutor(settings, client, clusterService, dataFrameAnalyticsManager.get(),
|
new TransportStartDataFrameAnalyticsAction.TaskExecutor(settings, client, clusterService, dataFrameAnalyticsManager.get(),
|
||||||
dataFrameAnalyticsAuditor.get(), memoryTracker.get(), expressionResolver)
|
dataFrameAnalyticsAuditor.get(), memoryTracker.get(), expressionResolver,
|
||||||
|
MlIndexTemplateRegistry.INFERENCE_TEMPLATE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class MlIndexTemplateRegistry extends IndexTemplateRegistry {
|
||||||
|
|
||||||
private static final IndexTemplateConfig CONFIG_TEMPLATE = configTemplate();
|
private static final IndexTemplateConfig CONFIG_TEMPLATE = configTemplate();
|
||||||
|
|
||||||
private static final IndexTemplateConfig INFERENCE_TEMPLATE = new IndexTemplateConfig(InferenceIndexConstants.LATEST_INDEX_NAME,
|
public static final IndexTemplateConfig INFERENCE_TEMPLATE = new IndexTemplateConfig(InferenceIndexConstants.LATEST_INDEX_NAME,
|
||||||
ROOT_RESOURCE_PATH + "inference_index_template.json", Version.CURRENT.id, VERSION_PATTERN,
|
ROOT_RESOURCE_PATH + "inference_index_template.json", Version.CURRENT.id, VERSION_PATTERN,
|
||||||
Collections.singletonMap(VERSION_ID_PATTERN, String.valueOf(Version.CURRENT.id)));
|
Collections.singletonMap(VERSION_ID_PATTERN, String.valueOf(Version.CURRENT.id)));
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,9 @@ import org.elasticsearch.xpack.core.ml.dataframe.analyses.RequiredField;
|
||||||
import org.elasticsearch.xpack.core.ml.job.messages.Messages;
|
import org.elasticsearch.xpack.core.ml.job.messages.Messages;
|
||||||
import org.elasticsearch.xpack.core.ml.job.persistence.AnomalyDetectorsIndex;
|
import org.elasticsearch.xpack.core.ml.job.persistence.AnomalyDetectorsIndex;
|
||||||
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.xpack.core.ml.utils.MlIndexAndAlias;
|
||||||
import org.elasticsearch.xpack.core.ml.utils.PhaseProgress;
|
import org.elasticsearch.xpack.core.ml.utils.PhaseProgress;
|
||||||
|
import org.elasticsearch.xpack.core.template.IndexTemplateConfig;
|
||||||
import org.elasticsearch.xpack.ml.MachineLearning;
|
import org.elasticsearch.xpack.ml.MachineLearning;
|
||||||
import org.elasticsearch.xpack.ml.dataframe.DataFrameAnalyticsManager;
|
import org.elasticsearch.xpack.ml.dataframe.DataFrameAnalyticsManager;
|
||||||
import org.elasticsearch.xpack.ml.dataframe.DataFrameAnalyticsTask;
|
import org.elasticsearch.xpack.ml.dataframe.DataFrameAnalyticsTask;
|
||||||
|
@ -594,6 +596,7 @@ public class TransportStartDataFrameAnalyticsAction
|
||||||
private final DataFrameAnalyticsAuditor auditor;
|
private final DataFrameAnalyticsAuditor auditor;
|
||||||
private final MlMemoryTracker memoryTracker;
|
private final MlMemoryTracker memoryTracker;
|
||||||
private final IndexNameExpressionResolver resolver;
|
private final IndexNameExpressionResolver resolver;
|
||||||
|
private final IndexTemplateConfig inferenceIndexTemplate;
|
||||||
|
|
||||||
private volatile int maxMachineMemoryPercent;
|
private volatile int maxMachineMemoryPercent;
|
||||||
private volatile int maxLazyMLNodes;
|
private volatile int maxLazyMLNodes;
|
||||||
|
@ -601,7 +604,8 @@ public class TransportStartDataFrameAnalyticsAction
|
||||||
private volatile ClusterState clusterState;
|
private volatile ClusterState clusterState;
|
||||||
|
|
||||||
public TaskExecutor(Settings settings, Client client, ClusterService clusterService, DataFrameAnalyticsManager manager,
|
public TaskExecutor(Settings settings, Client client, ClusterService clusterService, DataFrameAnalyticsManager manager,
|
||||||
DataFrameAnalyticsAuditor auditor, MlMemoryTracker memoryTracker, IndexNameExpressionResolver resolver) {
|
DataFrameAnalyticsAuditor auditor, MlMemoryTracker memoryTracker, IndexNameExpressionResolver resolver,
|
||||||
|
IndexTemplateConfig inferenceIndexTemplate) {
|
||||||
super(MlTasks.DATA_FRAME_ANALYTICS_TASK_NAME, MachineLearning.UTILITY_THREAD_POOL_NAME);
|
super(MlTasks.DATA_FRAME_ANALYTICS_TASK_NAME, MachineLearning.UTILITY_THREAD_POOL_NAME);
|
||||||
this.client = Objects.requireNonNull(client);
|
this.client = Objects.requireNonNull(client);
|
||||||
this.clusterService = Objects.requireNonNull(clusterService);
|
this.clusterService = Objects.requireNonNull(clusterService);
|
||||||
|
@ -609,6 +613,7 @@ public class TransportStartDataFrameAnalyticsAction
|
||||||
this.auditor = Objects.requireNonNull(auditor);
|
this.auditor = Objects.requireNonNull(auditor);
|
||||||
this.memoryTracker = Objects.requireNonNull(memoryTracker);
|
this.memoryTracker = Objects.requireNonNull(memoryTracker);
|
||||||
this.resolver = Objects.requireNonNull(resolver);
|
this.resolver = Objects.requireNonNull(resolver);
|
||||||
|
this.inferenceIndexTemplate = Objects.requireNonNull(inferenceIndexTemplate);
|
||||||
this.maxMachineMemoryPercent = MachineLearning.MAX_MACHINE_MEMORY_PERCENT.get(settings);
|
this.maxMachineMemoryPercent = MachineLearning.MAX_MACHINE_MEMORY_PERCENT.get(settings);
|
||||||
this.maxLazyMLNodes = MachineLearning.MAX_LAZY_ML_NODES.get(settings);
|
this.maxLazyMLNodes = MachineLearning.MAX_LAZY_ML_NODES.get(settings);
|
||||||
this.maxOpenJobs = MAX_OPEN_JOBS_PER_NODE.get(settings);
|
this.maxOpenJobs = MAX_OPEN_JOBS_PER_NODE.get(settings);
|
||||||
|
@ -693,6 +698,20 @@ public class TransportStartDataFrameAnalyticsAction
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ActionListener<Boolean> templateCheckListener = ActionListener.wrap(
|
||||||
|
ok -> executeTask(analyticsTaskState, task),
|
||||||
|
error -> {
|
||||||
|
Throwable cause = ExceptionsHelper.unwrapCause(error);
|
||||||
|
String msg = "Failed to create internal index template [" + inferenceIndexTemplate.getTemplateName() + "]";
|
||||||
|
logger.error(msg, cause);
|
||||||
|
task.markAsFailed(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
MlIndexAndAlias.installIndexTemplateIfRequired(clusterState, client, inferenceIndexTemplate, templateCheckListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeTask(DataFrameAnalyticsTaskState analyticsTaskState, AllocatedPersistentTask task) {
|
||||||
if (analyticsTaskState == null) {
|
if (analyticsTaskState == null) {
|
||||||
DataFrameAnalyticsTaskState startedState = new DataFrameAnalyticsTaskState(DataFrameAnalyticsState.STARTED,
|
DataFrameAnalyticsTaskState startedState = new DataFrameAnalyticsTaskState(DataFrameAnalyticsState.STARTED,
|
||||||
task.getAllocationId(), null);
|
task.getAllocationId(), null);
|
||||||
|
|
Loading…
Reference in New Issue