From f9dde666780131c6d36d6dad770759791358b31f Mon Sep 17 00:00:00 2001 From: David Roberts Date: Mon, 21 Nov 2016 11:26:10 +0000 Subject: [PATCH] Add a simple license validation argument to the C++ processes (elastic/elasticsearch#339) NOT the controller process, as this cannot take arguments when started as a daemon by Elasticsearch Closes elastic/elasticsearch#253 Original commit: elastic/x-pack-elasticsearch@14ea155caadb1974ae85cb08cf03e3a4ce3d0048 --- .../prelert/job/process/ProcessCtrl.java | 28 +++++++++++++------ .../prelert/job/process/ProcessCtrlTests.java | 23 +++++++++++++-- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrl.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrl.java index c43c0d6dac7..a8428209c71 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrl.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrl.java @@ -6,11 +6,13 @@ package org.elasticsearch.xpack.prelert.job.process; import org.apache.logging.log4j.Logger; +import org.elasticsearch.common.Randomness; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.monitor.jvm.JvmInfo; import org.elasticsearch.xpack.prelert.PrelertPlugin; import org.elasticsearch.xpack.prelert.job.AnalysisConfig; import org.elasticsearch.xpack.prelert.job.DataDescription; @@ -60,14 +62,16 @@ public class ProcessCtrl { public static final Setting MAX_ANOMALY_RECORDS_SETTING = Setting.intSetting("max.anomaly.records", DEFAULT_MAX_NUM_RECORDS, Property.NodeScope); - // TODO: remove once the C++ logger no longer needs it - static final String LOG_ID_ARG = "--logid="; + /** + * This must match the value defined in CLicenseValidator::validate() in the C++ code + */ + static final long VALIDATION_NUMBER = 926213; /* * General arguments */ static final String JOB_ID_ARG = "--jobid="; - + static final String LICENSE_VALIDATION_ARG = "--licenseValidation="; /* * Arguments used by both prelert_autodetect and prelert_normalize @@ -156,9 +160,7 @@ public class ProcessCtrl { String jobId = JOB_ID_ARG + job.getId(); command.add(jobId); - // the logging id is the job id - String logId = LOG_ID_ARG + job.getId(); - command.add(logId); + command.add(makeLicenseArg()); AnalysisConfig analysisConfig = job.getAnalysisConfig(); if (analysisConfig != null) { @@ -256,13 +258,13 @@ public class ProcessCtrl { /** * Build the command to start the normalizer process. */ - public static List buildNormaliserCommand(Environment env, String jobId, String quantilesState, Integer bucketSpan, + public static List buildNormaliserCommand(Environment env, String jobId, String quantilesState, Integer bucketSpan, boolean perPartitionNormalization, Logger logger) throws IOException { List command = new ArrayList<>(); command.add(NORMALIZE_PATH); addIfNotNull(bucketSpan, BUCKET_SPAN_ARG, command); - command.add(LOG_ID_ARG + jobId); + command.add(makeLicenseArg()); command.add(LENGTH_ENCODED_INPUT_ARG); if (perPartitionNormalization) { command.add(PER_PARTITION_NORMALIZATION); @@ -301,4 +303,14 @@ public class ProcessCtrl { return stateFile; } + + /** + * The number must be equal to the JVM PID modulo a magic number. + */ + private static String makeLicenseArg() { + // Get a random int rather than long so we don't overflow when multiplying by VALIDATION_NUMBER + long rand = Randomness.get().nextInt(); + long val = JvmInfo.jvmInfo().pid() + (((rand < 0) ? -rand : rand) + 1) * VALIDATION_NUMBER; + return LICENSE_VALIDATION_ARG + val; + } } diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrlTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrlTests.java index e2b504e03d6..28fd6816657 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrlTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/prelert/job/process/ProcessCtrlTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.xpack.prelert.job.process; import org.apache.logging.log4j.Logger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.monitor.jvm.JvmInfo; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.prelert.job.AnalysisConfig; import org.elasticsearch.xpack.prelert.job.DataDescription; @@ -72,7 +73,7 @@ public class ProcessCtrlTests extends ESTestCase { assertTrue(command.contains(ProcessCtrl.maxAnomalyRecordsArg(settings))); assertTrue(command.contains(ProcessCtrl.TIME_FIELD_ARG + "tf")); - assertTrue(command.contains(ProcessCtrl.LOG_ID_ARG + "unit-test-job")); + assertTrue(hasValidLicense(command)); assertTrue(command.contains(ProcessCtrl.JOB_ID_ARG + "unit-test-job")); assertTrue(command.contains(ProcessCtrl.PER_PARTITION_NORMALIZATION)); @@ -143,8 +144,26 @@ public class ProcessCtrlTests extends ESTestCase { assertEquals(5, command.size()); assertTrue(command.contains(ProcessCtrl.NORMALIZE_PATH)); assertTrue(command.contains(ProcessCtrl.BUCKET_SPAN_ARG + "300")); - assertTrue(command.contains(ProcessCtrl.LOG_ID_ARG + jobId)); + assertTrue(hasValidLicense(command)); assertTrue(command.contains(ProcessCtrl.LENGTH_ENCODED_INPUT_ARG)); assertTrue(command.contains(ProcessCtrl.PER_PARTITION_NORMALIZATION)); } + + private boolean hasValidLicense(List command) throws NumberFormatException { + int matches = 0; + for (String arg : command) { + if (arg.startsWith(ProcessCtrl.LICENSE_VALIDATION_ARG)) { + ++matches; + String[] argAndVal = arg.split("="); + if (argAndVal.length != 2) { + return false; + } + long val = Long.parseLong(argAndVal[1]); + if ((val % ProcessCtrl.VALIDATION_NUMBER) != (JvmInfo.jvmInfo().pid() % ProcessCtrl.VALIDATION_NUMBER)) { + return false; + } + } + } + return matches == 1; + } }