Use the correct Environment object in NativeControllerHolder (elastic/x-pack-elasticsearch#2847)

We should not be constructing a temporary Environment object in production
code.  This currently isn't causing any problems, but it might in the future
if elastic/elasticsearch#27144 or something similar is ever merged.  Instead
the master Environment of the node should always be used.

Original commit: elastic/x-pack-elasticsearch@6276a54a45
This commit is contained in:
David Roberts 2017-11-02 16:36:09 +00:00 committed by GitHub
parent 8888922af8
commit 14211b47f2
5 changed files with 37 additions and 25 deletions

View File

@ -313,7 +313,7 @@ public class MachineLearning implements ActionPlugin {
NormalizerProcessFactory normalizerProcessFactory; NormalizerProcessFactory normalizerProcessFactory;
if (AUTODETECT_PROCESS.get(settings) && MachineLearningFeatureSet.isRunningOnMlPlatform(true)) { if (AUTODETECT_PROCESS.get(settings) && MachineLearningFeatureSet.isRunningOnMlPlatform(true)) {
try { try {
NativeController nativeController = NativeControllerHolder.getNativeController(settings); NativeController nativeController = NativeControllerHolder.getNativeController(env);
if (nativeController == null) { if (nativeController == null) {
// This will only only happen when path.home is not set, which is disallowed in production // This will only only happen when path.home is not set, which is disallowed in production
throw new ElasticsearchException("Failed to create native process controller for Machine Learning"); throw new ElasticsearchException("Failed to create native process controller for Machine Learning");
@ -341,7 +341,7 @@ public class MachineLearning implements ActionPlugin {
DatafeedJobBuilder datafeedJobBuilder = new DatafeedJobBuilder(internalClient, jobProvider, auditor, System::currentTimeMillis); DatafeedJobBuilder datafeedJobBuilder = new DatafeedJobBuilder(internalClient, jobProvider, auditor, System::currentTimeMillis);
DatafeedManager datafeedManager = new DatafeedManager(threadPool, internalClient, clusterService, datafeedJobBuilder, DatafeedManager datafeedManager = new DatafeedManager(threadPool, internalClient, clusterService, datafeedJobBuilder,
System::currentTimeMillis, auditor, persistentTasksService); System::currentTimeMillis, auditor, persistentTasksService);
MlLifeCycleService mlLifeCycleService = new MlLifeCycleService(settings, clusterService, datafeedManager, autodetectProcessManager); MlLifeCycleService mlLifeCycleService = new MlLifeCycleService(env, clusterService, datafeedManager, autodetectProcessManager);
InvalidLicenseEnforcer invalidLicenseEnforcer = InvalidLicenseEnforcer invalidLicenseEnforcer =
new InvalidLicenseEnforcer(settings, licenseState, threadPool, datafeedManager, autodetectProcessManager); new InvalidLicenseEnforcer(settings, licenseState, threadPool, datafeedManager, autodetectProcessManager);
PersistentTasksExecutorRegistry persistentTasksExecutorRegistry = new PersistentTasksExecutorRegistry(Settings.EMPTY, Arrays.asList( PersistentTasksExecutorRegistry persistentTasksExecutorRegistry = new PersistentTasksExecutorRegistry(Settings.EMPTY, Arrays.asList(

View File

@ -20,6 +20,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.Loggers; 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.env.Environment;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.Platforms; import org.elasticsearch.plugins.Platforms;
import org.elasticsearch.xpack.XPackFeatureSet; import org.elasticsearch.xpack.XPackFeatureSet;
@ -64,9 +65,9 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
private final Map<String, Object> nativeCodeInfo; private final Map<String, Object> nativeCodeInfo;
@Inject @Inject
public MachineLearningFeatureSet(Settings settings, ClusterService clusterService, Client client, public MachineLearningFeatureSet(Environment environment, ClusterService clusterService, Client client,
@Nullable XPackLicenseState licenseState) { @Nullable XPackLicenseState licenseState) {
this.enabled = XPackSettings.MACHINE_LEARNING_ENABLED.get(settings); this.enabled = XPackSettings.MACHINE_LEARNING_ENABLED.get(environment.settings());
this.clusterService = Objects.requireNonNull(clusterService); this.clusterService = Objects.requireNonNull(clusterService);
this.client = Objects.requireNonNull(client); this.client = Objects.requireNonNull(client);
this.licenseState = licenseState; this.licenseState = licenseState;
@ -74,10 +75,11 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
// Don't try to get the native code version if ML is disabled - it causes too much controversy // Don't try to get the native code version if ML is disabled - it causes too much controversy
// if ML has been disabled because of some OS incompatibility. Also don't try to get the native // if ML has been disabled because of some OS incompatibility. Also don't try to get the native
// code version in the transport or tribe client - the controller process won't be running. // code version in the transport or tribe client - the controller process won't be running.
if (enabled && XPackPlugin.transportClientMode(settings) == false && XPackPlugin.isTribeClientNode(settings) == false) { if (enabled && XPackPlugin.transportClientMode(environment.settings()) == false
&& XPackPlugin.isTribeClientNode(environment.settings()) == false) {
try { try {
if (isRunningOnMlPlatform(true)) { if (isRunningOnMlPlatform(true)) {
NativeController nativeController = NativeControllerHolder.getNativeController(settings); NativeController nativeController = NativeControllerHolder.getNativeController(environment);
if (nativeController != null) { if (nativeController != null) {
nativeCodeInfo = nativeController.getNativeCodeInfo(); nativeCodeInfo = nativeController.getNativeCodeInfo();
} }

View File

@ -8,7 +8,7 @@ package org.elasticsearch.xpack.ml;
import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleListener; import org.elasticsearch.common.component.LifecycleListener;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.ml.datafeed.DatafeedManager; import org.elasticsearch.xpack.ml.datafeed.DatafeedManager;
import org.elasticsearch.xpack.ml.job.process.NativeController; import org.elasticsearch.xpack.ml.job.process.NativeController;
import org.elasticsearch.xpack.ml.job.process.NativeControllerHolder; import org.elasticsearch.xpack.ml.job.process.NativeControllerHolder;
@ -18,16 +18,18 @@ import java.io.IOException;
public class MlLifeCycleService extends AbstractComponent { public class MlLifeCycleService extends AbstractComponent {
private final Environment environment;
private final DatafeedManager datafeedManager; private final DatafeedManager datafeedManager;
private final AutodetectProcessManager autodetectProcessManager; private final AutodetectProcessManager autodetectProcessManager;
public MlLifeCycleService(Settings settings, ClusterService clusterService) { public MlLifeCycleService(Environment environment, ClusterService clusterService) {
this(settings, clusterService, null, null); this(environment, clusterService, null, null);
} }
public MlLifeCycleService(Settings settings, ClusterService clusterService, DatafeedManager datafeedManager, public MlLifeCycleService(Environment environment, ClusterService clusterService, DatafeedManager datafeedManager,
AutodetectProcessManager autodetectProcessManager) { AutodetectProcessManager autodetectProcessManager) {
super(settings); super(environment.settings());
this.environment = environment;
this.datafeedManager = datafeedManager; this.datafeedManager = datafeedManager;
this.autodetectProcessManager = autodetectProcessManager; this.autodetectProcessManager = autodetectProcessManager;
clusterService.addLifecycleListener(new LifecycleListener() { clusterService.addLifecycleListener(new LifecycleListener() {
@ -47,7 +49,7 @@ public class MlLifeCycleService extends AbstractComponent {
if (datafeedManager != null) { if (datafeedManager != null) {
datafeedManager.isolateAllDatafeedsOnThisNode(); datafeedManager.isolateAllDatafeedsOnThisNode();
} }
NativeController nativeController = NativeControllerHolder.getNativeController(settings); NativeController nativeController = NativeControllerHolder.getNativeController(environment);
if (nativeController != null) { if (nativeController != null) {
// This kills autodetect processes WITHOUT closing the jobs, so they get reallocated. // This kills autodetect processes WITHOUT closing the jobs, so they get reallocated.
if (autodetectProcessManager != null) { if (autodetectProcessManager != null) {

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.ml.job.process; package org.elasticsearch.xpack.ml.job.process;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.ml.MachineLearning; import org.elasticsearch.xpack.ml.MachineLearning;
import org.elasticsearch.xpack.ml.utils.NamedPipeHelper; import org.elasticsearch.xpack.ml.utils.NamedPipeHelper;
@ -29,16 +28,16 @@ public class NativeControllerHolder {
* *
* The NativeController is created lazily to allow time for the C++ process to be started before connection is attempted. * The NativeController is created lazily to allow time for the C++ process to be started before connection is attempted.
* *
* null is returned to tests that haven't bothered to set up path.home and all runs where xpack.ml.autodetect_process=false. * <code>null</code> is returned to tests where xpack.ml.autodetect_process=false.
* *
* Calls may throw an exception if initial connection to the C++ process fails. * Calls may throw an exception if initial connection to the C++ process fails.
*/ */
public static NativeController getNativeController(Settings settings) throws IOException { public static NativeController getNativeController(Environment environment) throws IOException {
if (Environment.PATH_HOME_SETTING.exists(settings) && MachineLearning.AUTODETECT_PROCESS.get(settings)) { if (MachineLearning.AUTODETECT_PROCESS.get(environment.settings())) {
synchronized (lock) { synchronized (lock) {
if (nativeController == null) { if (nativeController == null) {
nativeController = new NativeController(new Environment(settings), new NamedPipeHelper()); nativeController = new NativeController(environment, new NamedPipeHelper());
nativeController.tailLogsInThread(); nativeController.tailLogsInThread();
} }
} }
@ -51,7 +50,7 @@ public class NativeControllerHolder {
* Get a reference to the singleton native process controller. * Get a reference to the singleton native process controller.
* *
* Assumes that if it is possible for a native controller to exist that it will already have been created. * Assumes that if it is possible for a native controller to exist that it will already have been created.
* Designed for use by objects that don't have access to settings but know a native controller must exist * Designed for use by objects that don't have access to the environment but know a native controller must exist
* for the object calling this method to exist. * for the object calling this method to exist.
*/ */
public static NativeController getNativeController() { public static NativeController getNativeController() {

View File

@ -17,6 +17,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.env.Environment;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackFeatureSet; import org.elasticsearch.xpack.XPackFeatureSet;
@ -53,12 +54,17 @@ import static org.mockito.Mockito.when;
public class MachineLearningFeatureSetTests extends ESTestCase { public class MachineLearningFeatureSetTests extends ESTestCase {
private Settings commonSettings;
private ClusterService clusterService; private ClusterService clusterService;
private Client client; private Client client;
private XPackLicenseState licenseState; private XPackLicenseState licenseState;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
commonSettings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toAbsolutePath())
.put(MachineLearning.AUTODETECT_PROCESS.getKey(), false)
.build();
clusterService = mock(ClusterService.class); clusterService = mock(ClusterService.class);
client = mock(Client.class); client = mock(Client.class);
licenseState = mock(XPackLicenseState.class); licenseState = mock(XPackLicenseState.class);
@ -82,7 +88,8 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
} }
public void testAvailable() throws Exception { public void testAvailable() throws Exception {
MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(Settings.EMPTY, clusterService, client, licenseState); MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(new Environment(commonSettings), clusterService, client,
licenseState);
boolean available = randomBoolean(); boolean available = randomBoolean();
when(licenseState.isMachineLearningAllowed()).thenReturn(available); when(licenseState.isMachineLearningAllowed()).thenReturn(available);
assertThat(featureSet.available(), is(available)); assertThat(featureSet.available(), is(available));
@ -100,13 +107,14 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
public void testEnabled() throws Exception { public void testEnabled() throws Exception {
boolean useDefault = randomBoolean(); boolean useDefault = randomBoolean();
boolean enabled = true; boolean enabled = true;
Settings.Builder settings = Settings.builder(); Settings.Builder settings = Settings.builder().put(commonSettings);
if (useDefault == false) { if (useDefault == false) {
enabled = randomBoolean(); enabled = randomBoolean();
settings.put("xpack.ml.enabled", enabled); settings.put("xpack.ml.enabled", enabled);
} }
boolean expected = enabled || useDefault; boolean expected = enabled || useDefault;
MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(settings.build(), clusterService, client, licenseState); MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(new Environment(settings.build()), clusterService, client,
licenseState);
assertThat(featureSet.enabled(), is(expected)); assertThat(featureSet.enabled(), is(expected));
PlainActionFuture<Usage> future = new PlainActionFuture<>(); PlainActionFuture<Usage> future = new PlainActionFuture<>();
featureSet.usage(future); featureSet.usage(future);
@ -121,7 +129,7 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
public void testUsage() throws Exception { public void testUsage() throws Exception {
when(licenseState.isMachineLearningAllowed()).thenReturn(true); when(licenseState.isMachineLearningAllowed()).thenReturn(true);
Settings.Builder settings = Settings.builder(); Settings.Builder settings = Settings.builder().put(commonSettings);
settings.put("xpack.ml.enabled", true); settings.put("xpack.ml.enabled", true);
Job opened1 = buildJob("opened1", Arrays.asList(buildMinDetector("foo"))); Job opened1 = buildJob("opened1", Arrays.asList(buildMinDetector("foo")));
@ -139,7 +147,8 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
buildDatafeedStats(DatafeedState.STOPPED) buildDatafeedStats(DatafeedState.STOPPED)
)); ));
MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(settings.build(), clusterService, client, licenseState); MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(new Environment(settings.build()), clusterService, client,
licenseState);
PlainActionFuture<Usage> future = new PlainActionFuture<>(); PlainActionFuture<Usage> future = new PlainActionFuture<>();
featureSet.usage(future); featureSet.usage(future);
XPackFeatureSet.Usage mlUsage = future.get(); XPackFeatureSet.Usage mlUsage = future.get();
@ -201,11 +210,11 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
public void testUsageGivenMlMetadataNotInstalled() throws Exception { public void testUsageGivenMlMetadataNotInstalled() throws Exception {
when(licenseState.isMachineLearningAllowed()).thenReturn(true); when(licenseState.isMachineLearningAllowed()).thenReturn(true);
Settings.Builder settings = Settings.builder(); Settings.Builder settings = Settings.builder().put(commonSettings);
settings.put("xpack.ml.enabled", true); settings.put("xpack.ml.enabled", true);
when(clusterService.state()).thenReturn(ClusterState.EMPTY_STATE); when(clusterService.state()).thenReturn(ClusterState.EMPTY_STATE);
MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(settings.build(), MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(new Environment(settings.build()),
clusterService, client, licenseState); clusterService, client, licenseState);
PlainActionFuture<Usage> future = new PlainActionFuture<>(); PlainActionFuture<Usage> future = new PlainActionFuture<>();
featureSet.usage(future); featureSet.usage(future);