[ML] Be nicer on platforms that don't have the ML binaries (elastic/x-pack-elasticsearch#1060)

Following this change, if the user runs on a platform that we don't ship
ML binaries for:

* If ML is enabled the node still refuses to start, but clearly says why
* If ML is disabled the node starts up without logging any errors

Original commit: elastic/x-pack-elasticsearch@af4fb8c411
This commit is contained in:
David Roberts 2017-04-12 10:02:26 +01:00 committed by GitHub
parent 9d683dfe13
commit 17d9d6aea3
3 changed files with 48 additions and 6 deletions

View File

@ -272,7 +272,7 @@ public class MachineLearning implements ActionPlugin {
JobManager jobManager = new JobManager(settings, jobProvider, clusterService, auditor, internalClient, notifier); JobManager jobManager = new JobManager(settings, jobProvider, clusterService, auditor, internalClient, notifier);
AutodetectProcessFactory autodetectProcessFactory; AutodetectProcessFactory autodetectProcessFactory;
NormalizerProcessFactory normalizerProcessFactory; NormalizerProcessFactory normalizerProcessFactory;
if (AUTODETECT_PROCESS.get(settings)) { if (AUTODETECT_PROCESS.get(settings) && MachineLearningFeatureSet.isRunningOnMlPlatform(true)) {
try { try {
NativeController nativeController = NativeControllerHolder.getNativeController(settings); NativeController nativeController = NativeControllerHolder.getNativeController(settings);
if (nativeController == null) { if (nativeController == null) {

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.xpack.ml; package org.elasticsearch.xpack.ml;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.Counter; import org.apache.lucene.util.Counter;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
@ -19,6 +20,7 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.Platforms;
import org.elasticsearch.xpack.XPackFeatureSet; import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
@ -33,6 +35,7 @@ import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSizeStats;
import org.elasticsearch.xpack.ml.utils.StatsAccumulator; import org.elasticsearch.xpack.ml.utils.StatsAccumulator;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -47,6 +50,12 @@ import static org.elasticsearch.xpack.ml.action.GetJobsStatsAction.Response.JobS
public class MachineLearningFeatureSet implements XPackFeatureSet { public class MachineLearningFeatureSet implements XPackFeatureSet {
/**
* List of platforms for which the native processes are available
*/
private static final List<String> mlPlatforms =
Arrays.asList("darwin-x86_64", "linux-x86_64", "windows-x86_64");
private final boolean enabled; private final boolean enabled;
private final XPackLicenseState licenseState; private final XPackLicenseState licenseState;
private final ClusterService clusterService; private final ClusterService clusterService;
@ -64,21 +73,38 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
// Don't try to get the native code version in the transport client - the controller process won't be running // Don't try to get the native code version in the transport client - the controller process won't be running
if (XPackPlugin.transportClientMode(settings) == false && XPackPlugin.isTribeClientNode(settings) == false) { if (XPackPlugin.transportClientMode(settings) == false && XPackPlugin.isTribeClientNode(settings) == false) {
try { try {
if (isRunningOnMlPlatform(enabled)) {
NativeController nativeController = NativeControllerHolder.getNativeController(settings); NativeController nativeController = NativeControllerHolder.getNativeController(settings);
if (nativeController != null) { if (nativeController != null) {
nativeCodeInfo = nativeController.getNativeCodeInfo(); nativeCodeInfo = nativeController.getNativeCodeInfo();
} }
}
} catch (IOException | TimeoutException e) { } catch (IOException | TimeoutException e) {
Loggers.getLogger(MachineLearningFeatureSet.class).error("Cannot get native code info for Machine Learning", e); Loggers.getLogger(MachineLearningFeatureSet.class).error("Cannot get native code info for Machine Learning", e);
if (enabled) { if (enabled) {
throw new ElasticsearchException("Cannot communicate with Machine Learning native code " throw new ElasticsearchException("Cannot communicate with Machine Learning native code");
+ "- please check that you are running on a supported platform");
} }
} }
} }
this.nativeCodeInfo = nativeCodeInfo; this.nativeCodeInfo = nativeCodeInfo;
} }
static boolean isRunningOnMlPlatform(boolean fatalIfNot) {
return isRunningOnMlPlatform(Constants.OS_NAME, Constants.OS_ARCH, fatalIfNot);
}
static boolean isRunningOnMlPlatform(String osName, String osArch, boolean fatalIfNot) {
String platformName = Platforms.platformName(osName, osArch);
if (mlPlatforms.contains(platformName)) {
return true;
}
if (fatalIfNot) {
throw new ElasticsearchException("X-Pack is not supported and Machine Learning is not available for [" + platformName
+ "]; you can use the other X-Pack features (unsupported) by setting xpack.ml.enabled: false in elasticsearch.yml");
}
return false;
}
@Override @Override
public String name() { public String name() {
return XPackPlugin.MACHINE_LEARNING; return XPackPlugin.MACHINE_LEARNING;

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.xpack.ml; package org.elasticsearch.xpack.ml;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.action.support.PlainActionFuture;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
@ -64,6 +65,21 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
givenDatafeeds(Collections.emptyList()); givenDatafeeds(Collections.emptyList());
} }
public void testIsRunningOnMlPlatform() {
assertTrue(MachineLearningFeatureSet.isRunningOnMlPlatform("Linux", "amd64", true));
assertTrue(MachineLearningFeatureSet.isRunningOnMlPlatform("Windows 10", "amd64", true));
assertTrue(MachineLearningFeatureSet.isRunningOnMlPlatform("Mac OS X", "x86_64", true));
assertFalse(MachineLearningFeatureSet.isRunningOnMlPlatform("Linux", "i386", false));
assertFalse(MachineLearningFeatureSet.isRunningOnMlPlatform("Windows 10", "i386", false));
assertFalse(MachineLearningFeatureSet.isRunningOnMlPlatform("SunOS", "amd64", false));
expectThrows(ElasticsearchException.class,
() -> MachineLearningFeatureSet.isRunningOnMlPlatform("Linux", "i386", true));
expectThrows(ElasticsearchException.class,
() -> MachineLearningFeatureSet.isRunningOnMlPlatform("Windows 10", "i386", true));
expectThrows(ElasticsearchException.class,
() -> MachineLearningFeatureSet.isRunningOnMlPlatform("SunOS", "amd64", true));
}
public void testAvailable() throws Exception { public void testAvailable() throws Exception {
MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(Settings.EMPTY, clusterService, client, licenseState); MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(Settings.EMPTY, clusterService, client, licenseState);
boolean available = randomBoolean(); boolean available = randomBoolean();