From 06a0a9cbb584268ec494ec75728574a8c9b79152 Mon Sep 17 00:00:00 2001 From: uboness Date: Fri, 22 Apr 2016 14:35:46 -0700 Subject: [PATCH 01/16] [fix] Removing license did not update the Licensees - Introduced a `MISSING` operation mode - now when the license is removed (and a tombstone license is placed), the licensees get notified with a `MISSING` license status - the monitoring, security and watcher licensees were updated Original commit: elastic/x-pack-elasticsearch@650d9406665e7eb0d98aa43a300f3f5eaea3b548 --- .../elasticsearch/license/core/License.java | 3 + .../license/plugin/core/Licensee.java | 1 + .../license/plugin/core/LicensesService.java | 139 ++++++++++-------- .../license/plugin/TestUtils.java | 5 +- .../core/LicensesExpiryNotificationTests.java | 70 +++++---- .../core/LicensesManagerServiceTests.java | 52 ++++++- .../marvel/MonitoringFeatureSet.java | 2 +- .../marvel/MonitoringLicensee.java | 6 +- .../xpack/watcher/WatcherFeatureSet.java | 2 +- .../xpack/watcher/WatcherLicensee.java | 18 ++- 10 files changed, 191 insertions(+), 107 deletions(-) diff --git a/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java b/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java index 4f503f68073..6e9e9fd4816 100644 --- a/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java +++ b/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java @@ -77,6 +77,7 @@ public class License implements ToXContent { * Note: The mode indicates features that should be made available, but it does not indicate whether the license is active! */ public enum OperationMode { + MISSING, TRIAL, BASIC, STANDARD, @@ -85,6 +86,8 @@ public class License implements ToXContent { public static OperationMode resolve(String type) { switch (type.toLowerCase(Locale.ROOT)) { + case "missing": + return MISSING; case "trial": case "none": // bwc for 1.x subscription_type field case "dev": // bwc for 1.x subscription_type field diff --git a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java index 3e32e0aa5e8..cadeb922568 100644 --- a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java +++ b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java @@ -53,6 +53,7 @@ public interface Licensee { class Status { public static Status ENABLED = new Status(OperationMode.TRIAL, LicenseState.ENABLED); + public static Status MISSING = new Status(OperationMode.MISSING, LicenseState.DISABLED); private final OperationMode mode; private final LicenseState licenseState; diff --git a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java index fe0be8763b5..db47a811de7 100644 --- a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java +++ b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java @@ -511,72 +511,77 @@ public class LicensesService extends AbstractLifecycleComponent */ private void notifyAndSchedule(final LicensesMetaData currentLicensesMetaData) { final License license = getLicense(currentLicensesMetaData); - if (license != null) { - logger.debug("notifying [{}] listeners", registeredLicensees.size()); - long now = System.currentTimeMillis(); - if (license.issueDate() > now) { - logger.info("license [{}] - invalid", license.uid()); - return; + if (license == null) { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onRemove(); } - long expiryDuration = license.expiryDate() - now; - if (license.expiryDate() > now) { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onChange(license, LicenseState.ENABLED); - } - logger.info("license [{}] - valid", license.uid()); - final TimeValue delay = TimeValue.timeValueMillis(expiryDuration); - // cancel any previous notifications - cancelNotifications(expiryNotifications); - try { - logger.debug("schedule grace notification after [{}] for license [{}]", delay.toString(), license.uid()); - expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); - } catch (EsRejectedExecutionException ex) { - logger.debug("couldn't schedule grace notification", ex); - } - } else if ((license.expiryDate() + gracePeriodDuration.getMillis()) > now) { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onChange(license, LicenseState.GRACE_PERIOD); - } - logger.info("license [{}] - grace", license.uid()); - final TimeValue delay = TimeValue.timeValueMillis(expiryDuration + gracePeriodDuration.getMillis()); - // cancel any previous notifications - cancelNotifications(expiryNotifications); - try { - logger.debug("schedule expiry notification after [{}] for license [{}]", delay.toString(), license.uid()); - expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); - } catch (EsRejectedExecutionException ex) { - logger.debug("couldn't schedule expiry notification", ex); - } - } else { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onChange(license, LicenseState.DISABLED); - } - logger.info("license [{}] - expired", license.uid()); + return; + } + + logger.debug("notifying [{}] listeners", registeredLicensees.size()); + long now = System.currentTimeMillis(); + if (license.issueDate() > now) { + logger.info("license [{}] - invalid", license.uid()); + return; + } + long expiryDuration = license.expiryDate() - now; + if (license.expiryDate() > now) { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onChange(license, LicenseState.ENABLED); } - if (!license.equals(currentLicense.get())) { - currentLicense.set(license); - // cancel all scheduled event notifications - cancelNotifications(eventNotifications); - // schedule expiry callbacks - for (ExpirationCallback expirationCallback : this.expirationCallbacks) { - final TimeValue delay; - if (expirationCallback.matches(license.expiryDate(), now)) { - expirationCallback.on(license); - TimeValue frequency = expirationCallback.frequency(); - delay = frequency != null ? frequency : expirationCallback.delay(expiryDuration); - } else { - delay = expirationCallback.delay(expiryDuration); - } - if (delay != null) { - eventNotifications.add(threadPool.schedule(delay, executorName(), new EventNotificationJob(expirationCallback))); - } - if (logger.isDebugEnabled()) { - logger.debug("schedule [{}] after [{}]", expirationCallback, delay); - } - } - logger.debug("scheduled expiry callbacks for [{}] expiring after [{}]", license.uid(), - TimeValue.timeValueMillis(expiryDuration)); + logger.info("license [{}] - valid", license.uid()); + final TimeValue delay = TimeValue.timeValueMillis(expiryDuration); + // cancel any previous notifications + cancelNotifications(expiryNotifications); + try { + logger.debug("schedule grace notification after [{}] for license [{}]", delay.toString(), license.uid()); + expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); + } catch (EsRejectedExecutionException ex) { + logger.debug("couldn't schedule grace notification", ex); } + } else if ((license.expiryDate() + gracePeriodDuration.getMillis()) > now) { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onChange(license, LicenseState.GRACE_PERIOD); + } + logger.info("license [{}] - grace", license.uid()); + final TimeValue delay = TimeValue.timeValueMillis(expiryDuration + gracePeriodDuration.getMillis()); + // cancel any previous notifications + cancelNotifications(expiryNotifications); + try { + logger.debug("schedule expiry notification after [{}] for license [{}]", delay.toString(), license.uid()); + expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); + } catch (EsRejectedExecutionException ex) { + logger.debug("couldn't schedule expiry notification", ex); + } + } else { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onChange(license, LicenseState.DISABLED); + } + logger.info("license [{}] - expired", license.uid()); + } + if (!license.equals(currentLicense.get())) { + currentLicense.set(license); + // cancel all scheduled event notifications + cancelNotifications(eventNotifications); + // schedule expiry callbacks + for (ExpirationCallback expirationCallback : this.expirationCallbacks) { + final TimeValue delay; + if (expirationCallback.matches(license.expiryDate(), now)) { + expirationCallback.on(license); + TimeValue frequency = expirationCallback.frequency(); + delay = frequency != null ? frequency : expirationCallback.delay(expiryDuration); + } else { + delay = expirationCallback.delay(expiryDuration); + } + if (delay != null) { + eventNotifications.add(threadPool.schedule(delay, executorName(), new EventNotificationJob(expirationCallback))); + } + if (logger.isDebugEnabled()) { + logger.debug("schedule [{}] after [{}]", expirationCallback, delay); + } + } + logger.debug("scheduled expiry callbacks for [{}] expiring after [{}]", license.uid(), + TimeValue.timeValueMillis(expiryDuration)); } } @@ -845,6 +850,14 @@ public class LicensesService extends AbstractLifecycleComponent } } } + + public void onRemove() { + synchronized (this) { + currentLicense = null; + currentLicenseState = null; + licensee.onChange(Licensee.Status.MISSING); + } + } } /** diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/TestUtils.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/TestUtils.java index eb9fb0adf00..0dc69597a89 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/TestUtils.java +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/TestUtils.java @@ -23,7 +23,6 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.license.core.License; import org.elasticsearch.license.licensor.LicenseSigner; import org.elasticsearch.license.plugin.action.put.PutLicenseRequest; -import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.Licensee; import org.elasticsearch.license.plugin.core.LicensesService; import org.elasticsearch.license.plugin.core.LicensesStatus; @@ -162,7 +161,7 @@ public class TestUtils { public static class AssertingLicensee implements Licensee { public final ESLogger logger; public final String id; - public final List licenseStates = new CopyOnWriteArrayList<>(); + public final List statuses = new CopyOnWriteArrayList<>(); public final AtomicInteger expirationMessagesCalled = new AtomicInteger(0); public final List> acknowledgementRequested = new CopyOnWriteArrayList<>(); @@ -196,7 +195,7 @@ public class TestUtils { @Override public void onChange(Status status) { assertNotNull(status); - licenseStates.add(status.getLicenseState()); + statuses.add(status); } } } diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java index 9852b58c5ce..9e019976129 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java @@ -11,7 +11,9 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.license.plugin.TestUtils.AssertingLicensee; import org.elasticsearch.test.ESSingleNodeTestCase; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import static org.elasticsearch.license.plugin.TestUtils.awaitNoBlock; import static org.elasticsearch.license.plugin.TestUtils.awaitNoPendingTasks; @@ -41,10 +43,10 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { awaitNoBlock(client()); licensesService.register(licensee); awaitNoPendingTasks(client()); - boolean success = awaitBusy(() -> licensee.licenseStates.size() == 3); + boolean success = awaitBusy(() -> licensee.statuses.size() == 3); // trail license: enable, grace, disabled assertLicenseStates(licensee, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + assertTrue(dumpLicensingStates(licensee.statuses), success); licensesService.stop(); } @@ -61,10 +63,10 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { licensesService.register(licensee1); licensesService.register(licensee2); awaitNoPendingTasks(client()); - boolean success = awaitBusy(() -> licensee1.licenseStates.size() == 3); - assertTrue(dumpLicensingStates(licensee1.licenseStates), success); - success = awaitBusy(() -> licensee2.licenseStates.size() == 3); - assertTrue(dumpLicensingStates(licensee2.licenseStates), success); + boolean success = awaitBusy(() -> licensee1.statuses.size() == 3); + assertTrue(dumpLicensingStates(licensee1.statuses), success); + success = awaitBusy(() -> licensee2.statuses.size() == 3); + assertTrue(dumpLicensingStates(licensee2.statuses), success); // trail license: enable, grace, disabled assertLicenseStates(licensee1, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); assertLicenseStates(licensee2, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); @@ -81,13 +83,13 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { awaitNoBlock(client()); licensesService.register(licensee); awaitNoPendingTasks(client()); - boolean success = awaitBusy(() -> licensee.licenseStates.size() == 1); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + boolean success = awaitBusy(() -> licensee.statuses.size() == 1); + assertTrue(dumpLicensingStates(licensee.statuses), success); registerAndAckSignedLicenses(licensesService, generateSignedLicense(TimeValue.timeValueSeconds(4)), LicensesStatus.VALID); - success = awaitBusy(() -> licensee.licenseStates.size() == 4); + success = awaitBusy(() -> licensee.statuses.size() == 4); // trial: enable, signed: enable, signed: grace, signed: disabled assertLicenseStates(licensee, LicenseState.ENABLED, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + assertTrue(dumpLicensingStates(licensee.statuses), success); licensesService.stop(); } @@ -102,10 +104,10 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { registerAndAckSignedLicenses(licensesService, generateSignedLicense(TimeValue.timeValueSeconds(2)), LicensesStatus.VALID); licensesService.register(licensee); awaitNoPendingTasks(client()); - boolean success = awaitBusy(() -> licensee.licenseStates.size() == 3); + boolean success = awaitBusy(() -> licensee.statuses.size() == 3); // signed: enable, signed: grace, signed: disabled assertLicenseStates(licensee, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + assertTrue(dumpLicensingStates(licensee.statuses), success); licensesService.stop(); } @@ -123,10 +125,10 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { licensesService.register(licensee1); licensesService.register(licensee2); awaitNoPendingTasks(client()); - boolean success = awaitBusy(() -> licensee1.licenseStates.size() == 3); - assertTrue(dumpLicensingStates(licensee1.licenseStates), success); - success = awaitBusy(() -> licensee2.licenseStates.size() == 3); - assertTrue(dumpLicensingStates(licensee2.licenseStates), success); + boolean success = awaitBusy(() -> licensee1.statuses.size() == 3); + assertTrue(dumpLicensingStates(licensee1.statuses), success); + success = awaitBusy(() -> licensee2.statuses.size() == 3); + assertTrue(dumpLicensingStates(licensee2.statuses), success); // signed license: enable, grace, disabled assertLicenseStates(licensee1, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); assertLicenseStates(licensee2, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); @@ -145,18 +147,18 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { licensesService.register(licensee); awaitNoPendingTasks(client()); // trial license enabled - boolean success = awaitBusy(() -> licensee.licenseStates.size() == 1); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + boolean success = awaitBusy(() -> licensee.statuses.size() == 1); + assertTrue(dumpLicensingStates(licensee.statuses), success); registerAndAckSignedLicenses(licensesService, generateSignedLicense("basic", TimeValue.timeValueSeconds(3)), LicensesStatus.VALID); // signed license enabled - success = awaitBusy(() -> licensee.licenseStates.size() == 2); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + success = awaitBusy(() -> licensee.statuses.size() == 2); + assertTrue(dumpLicensingStates(licensee.statuses), success); registerAndAckSignedLicenses(licensesService, generateSignedLicense("gold", TimeValue.timeValueSeconds(2)), LicensesStatus.VALID); // second signed license enabled, grace and expired - success = awaitBusy(() ->licensee.licenseStates.size() == 5); + success = awaitBusy(() ->licensee.statuses.size() == 5); assertLicenseStates(licensee, LicenseState.ENABLED, LicenseState.ENABLED, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + assertTrue(dumpLicensingStates(licensee.statuses), success); licensesService.stop(); } @@ -171,33 +173,39 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { awaitNoBlock(client()); licensesService.register(licensee); // trial license: enabled, grace, disabled - boolean success = awaitBusy(() -> licensee.licenseStates.size() == 3); + boolean success = awaitBusy(() -> licensee.statuses.size() == 3); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + assertTrue(dumpLicensingStates(licensee.statuses), success); // install license registerAndAckSignedLicenses(licensesService, generateSignedLicense("basic", TimeValue.timeValueSeconds(2)), LicensesStatus.VALID); // trial license: enabled, grace, disabled, signed license: enabled, grace, disabled - success = awaitBusy(() -> licensee.licenseStates.size() == 6); + success = awaitBusy(() -> licensee.statuses.size() == 6); assertLicenseStates(licensee, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED, LicenseState.ENABLED, LicenseState.GRACE_PERIOD, LicenseState.DISABLED); - assertTrue(dumpLicensingStates(licensee.licenseStates), success); + assertTrue(dumpLicensingStates(licensee.statuses), success); licensesService.stop(); } private void assertLicenseStates(AssertingLicensee licensee, LicenseState... states) { StringBuilder msg = new StringBuilder(); msg.append("Actual: "); - msg.append(dumpLicensingStates(licensee.licenseStates)); + msg.append(dumpLicensingStates(licensee.statuses)); msg.append(" Expected: "); msg.append(dumpLicensingStates(states)); - assertThat(msg.toString(), licensee.licenseStates.size(), equalTo(states.length)); + assertThat(msg.toString(), licensee.statuses.size(), equalTo(states.length)); for (int i = 0; i < states.length; i++) { - assertThat(msg.toString(), licensee.licenseStates.get(i), equalTo(states[i])); + assertThat(msg.toString(), licensee.statuses.get(i), equalTo(states[i])); } } - private String dumpLicensingStates(List states) { - return dumpLicensingStates(states.toArray(new LicenseState[states.size()])); + private String dumpLicensingStates(List statuses) { + return dumpLicensingStates(statuses.toArray(new Licensee.Status[statuses.size()])); + } + + + private String dumpLicensingStates(Licensee.Status... statuses) { + return dumpLicensingStates((LicenseState[]) Arrays.asList(statuses).stream() + .map(Licensee.Status::getLicenseState).collect(Collectors.toList()).toArray()); } private String dumpLicensingStates(LicenseState... states) { diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java index 0f62925def7..60912e03a95 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java @@ -6,9 +6,9 @@ package org.elasticsearch.license.plugin.core; import org.elasticsearch.action.ActionListener; -import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse; import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.license.core.License; import org.elasticsearch.license.plugin.TestUtils; @@ -20,9 +20,12 @@ import java.util.concurrent.atomic.AtomicBoolean; import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; public class LicensesManagerServiceTests extends ESSingleNodeTestCase { + static { MetaData.registerPrototype(LicensesMetaData.TYPE, LicensesMetaData.PROTO); } @@ -111,6 +114,53 @@ public class LicensesManagerServiceTests extends ESSingleNodeTestCase { assertThat(licensesMetaData.getLicense(), equalTo(LicensesMetaData.LICENSE_TOMBSTONE)); } + public void testRemoveLicensesAndLicenseeNotification() throws Exception { + LicensesService licensesService = getInstanceFromNode(LicensesService.class); + licensesService.start(); + ClusterService clusterService = getInstanceFromNode(ClusterService.class); + + // generate a trial license for one feature + TestUtils.AssertingLicensee licensee = new TestUtils.AssertingLicensee("", logger); + licensesService.register(licensee); + + // we should get a trial license to begin with + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(licensee.statuses, hasSize(1)); + assertThat(licensee.statuses.get(0).getMode(), is(License.OperationMode.TRIAL)); + assertThat(licensee.statuses.get(0).getLicenseState(), is(LicenseState.ENABLED)); + } + }); + + + // generate signed licenses + License license = generateSignedLicense(TimeValue.timeValueHours(1)); + TestUtils.registerAndAckSignedLicenses(licensesService, license, LicensesStatus.VALID); + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(licensee.statuses, hasSize(2)); + assertThat(licensee.statuses.get(1).getMode(), not(License.OperationMode.TRIAL)); + assertThat(licensee.statuses.get(1).getLicenseState(), is(LicenseState.ENABLED)); + } + }); + + // remove signed licenses + removeAndAckSignedLicenses(licensesService); + assertBusy(new Runnable() { + @Override + public void run() { + assertThat(licensee.statuses, hasSize(3)); + } + }); + LicensesMetaData licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); + assertThat(licensesMetaData.getLicense(), is(LicensesMetaData.LICENSE_TOMBSTONE)); + assertThat(licensee.statuses, hasSize(3)); + assertThat(licensee.statuses.get(2).getLicenseState(), is(LicenseState.DISABLED)); + assertThat(licensee.statuses.get(2).getMode(), is(License.OperationMode.MISSING)); + } + private void removeAndAckSignedLicenses(final LicensesService licensesService) { final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean success = new AtomicBoolean(false); diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java index c8b6dd29005..03a4b61b7b8 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java @@ -36,7 +36,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet { @Override public boolean available() { - return licensee != null && licensee.available(); + return licensee != null && licensee.isAvailable(); } @Override diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java index e73a8f40321..105f001d21f 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java @@ -75,12 +75,12 @@ public class MonitoringLicensee extends AbstractLicenseeComponent * * @return {@code true} as long as the license is valid. Otherwise {@code false}. */ - public boolean available() { + public boolean isAvailable() { // status is volatile, so a local variable is used for a consistent view Status localStatus = status; - return localStatus.getLicenseState() != LicenseState.DISABLED && (localStatus.getMode() == OperationMode.TRIAL || - localStatus.getMode() == OperationMode.GOLD || localStatus.getMode() == OperationMode.PLATINUM); + if (localStatus.getLicenseState() == LicenseState.DISABLED) { + return false; + } + + switch (localStatus.getMode()) { + case TRIAL: + case GOLD: + case PLATINUM: + return true; + default: + return false; + } } public boolean isExecutingActionsAllowed() { @@ -84,7 +94,7 @@ public class WatcherLicensee extends AbstractLicenseeComponent public boolean isWatcherTransportActionAllowed() { - return available(); + return isAvailable(); } From 01b3fc8768764033a95b05f217288933d6bb9bf3 Mon Sep 17 00:00:00 2001 From: Areek Zillur Date: Tue, 10 May 2016 16:43:28 -0400 Subject: [PATCH 02/16] Differentiate between null license and license tombstone in cluster state Currently, license notification scheme treats no license (before trial license is auto-generated) and a license tombstone in the cluster state in the same way. This caused a bug where licencees were not notified of explicit license removal. Now, the notification scheme explicitly handles license tombstone to notify the licensees and handles the case for no license in cluster state as before. Original commit: elastic/x-pack-elasticsearch@c90ec23398ad7cba55efa382652e87796498355d --- .../license/plugin/core/LicensesService.java | 186 +++++++++--------- .../core/LicensesManagerServiceTests.java | 2 +- .../marvel/MonitoringLicensee.java | 5 +- .../marvel/license/MarvelLicenseeTests.java | 9 +- .../shield/ShieldLicenseeTests.java | 3 +- 5 files changed, 110 insertions(+), 95 deletions(-) diff --git a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java index db47a811de7..a5cef03a4a2 100644 --- a/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java +++ b/elasticsearch/x-pack/license-plugin/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java @@ -262,25 +262,26 @@ public class LicensesService extends AbstractLifecycleComponent if (!request.acknowledged()) { final LicensesMetaData currentMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); final License currentLicense = getLicense(currentMetaData); - Map acknowledgeMessages = new HashMap<>(registeredLicensees.size() + 1); - if (currentLicense != null && !License.isAutoGeneratedLicense(currentLicense.signature()) // when current license is not - // an auto-generated license - && currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date - acknowledgeMessages.put("license", - new String[]{"The new license is older than the currently installed license. Are you sure you want to " + - "override the current license?"}); - } - for (InternalLicensee licensee : registeredLicensees) { - String[] listenerAcknowledgeMessages = licensee.acknowledgmentMessages(currentLicense, newLicense); - if (listenerAcknowledgeMessages.length > 0) { - acknowledgeMessages.put(licensee.id(), listenerAcknowledgeMessages); + if (currentLicense != null && currentLicense != LicensesMetaData.LICENSE_TOMBSTONE) { + Map acknowledgeMessages = new HashMap<>(registeredLicensees.size() + 1); + if (!License.isAutoGeneratedLicense(currentLicense.signature()) // current license is not auto-generated + && currentLicense.issueDate() > newLicense.issueDate()) { // and has a later issue date + acknowledgeMessages.put("license", + new String[]{"The new license is older than the currently installed license. Are you sure you want to " + + "override the current license?"}); + } + for (InternalLicensee licensee : registeredLicensees) { + String[] listenerAcknowledgeMessages = licensee.acknowledgmentMessages(currentLicense, newLicense); + if (listenerAcknowledgeMessages.length > 0) { + acknowledgeMessages.put(licensee.id(), listenerAcknowledgeMessages); + } + } + if (!acknowledgeMessages.isEmpty()) { + // needs acknowledgement + listener.onResponse(new LicensesUpdateResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER, + acknowledgeMessages)); + return; } - } - if (!acknowledgeMessages.isEmpty()) { - // needs acknowledgement - listener.onResponse(new LicensesUpdateResponse(false, LicensesStatus.VALID, ACKNOWLEDGEMENT_HEADER, - acknowledgeMessages)); - return; } } clusterService.submitStateUpdateTask("register license [" + newLicense.uid() + "]", new @@ -385,8 +386,8 @@ public class LicensesService extends AbstractLifecycleComponent @Override public License getLicense() { - final LicensesMetaData metaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); - return getLicense(metaData); + final License license = getLicense(clusterService.state().metaData().custom(LicensesMetaData.TYPE)); + return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license; } /** @@ -511,77 +512,80 @@ public class LicensesService extends AbstractLifecycleComponent */ private void notifyAndSchedule(final LicensesMetaData currentLicensesMetaData) { final License license = getLicense(currentLicensesMetaData); - if (license == null) { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onRemove(); - } + if (license == LicensesMetaData.LICENSE_TOMBSTONE) { + // implies license has been explicitly deleted + // update licensee states + registeredLicensees.forEach(InternalLicensee::onRemove); return; } - - logger.debug("notifying [{}] listeners", registeredLicensees.size()); - long now = System.currentTimeMillis(); - if (license.issueDate() > now) { - logger.info("license [{}] - invalid", license.uid()); - return; - } - long expiryDuration = license.expiryDate() - now; - if (license.expiryDate() > now) { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onChange(license, LicenseState.ENABLED); + // license can be null if the trial license is yet to be auto-generated + // in this case, it is a no-op + if (license != null) { + logger.debug("notifying [{}] listeners", registeredLicensees.size()); + long now = System.currentTimeMillis(); + if (license.issueDate() > now) { + logger.info("license [{}] - invalid", license.uid()); + return; } - logger.info("license [{}] - valid", license.uid()); - final TimeValue delay = TimeValue.timeValueMillis(expiryDuration); - // cancel any previous notifications - cancelNotifications(expiryNotifications); - try { - logger.debug("schedule grace notification after [{}] for license [{}]", delay.toString(), license.uid()); - expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); - } catch (EsRejectedExecutionException ex) { - logger.debug("couldn't schedule grace notification", ex); - } - } else if ((license.expiryDate() + gracePeriodDuration.getMillis()) > now) { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onChange(license, LicenseState.GRACE_PERIOD); - } - logger.info("license [{}] - grace", license.uid()); - final TimeValue delay = TimeValue.timeValueMillis(expiryDuration + gracePeriodDuration.getMillis()); - // cancel any previous notifications - cancelNotifications(expiryNotifications); - try { - logger.debug("schedule expiry notification after [{}] for license [{}]", delay.toString(), license.uid()); - expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); - } catch (EsRejectedExecutionException ex) { - logger.debug("couldn't schedule expiry notification", ex); - } - } else { - for (InternalLicensee licensee : registeredLicensees) { - licensee.onChange(license, LicenseState.DISABLED); - } - logger.info("license [{}] - expired", license.uid()); - } - if (!license.equals(currentLicense.get())) { - currentLicense.set(license); - // cancel all scheduled event notifications - cancelNotifications(eventNotifications); - // schedule expiry callbacks - for (ExpirationCallback expirationCallback : this.expirationCallbacks) { - final TimeValue delay; - if (expirationCallback.matches(license.expiryDate(), now)) { - expirationCallback.on(license); - TimeValue frequency = expirationCallback.frequency(); - delay = frequency != null ? frequency : expirationCallback.delay(expiryDuration); - } else { - delay = expirationCallback.delay(expiryDuration); + long expiryDuration = license.expiryDate() - now; + if (license.expiryDate() > now) { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onChange(license, LicenseState.ENABLED); } - if (delay != null) { - eventNotifications.add(threadPool.schedule(delay, executorName(), new EventNotificationJob(expirationCallback))); + logger.info("license [{}] - valid", license.uid()); + final TimeValue delay = TimeValue.timeValueMillis(expiryDuration); + // cancel any previous notifications + cancelNotifications(expiryNotifications); + try { + logger.debug("schedule grace notification after [{}] for license [{}]", delay.toString(), license.uid()); + expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); + } catch (EsRejectedExecutionException ex) { + logger.debug("couldn't schedule grace notification", ex); } - if (logger.isDebugEnabled()) { - logger.debug("schedule [{}] after [{}]", expirationCallback, delay); + } else if ((license.expiryDate() + gracePeriodDuration.getMillis()) > now) { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onChange(license, LicenseState.GRACE_PERIOD); } + logger.info("license [{}] - grace", license.uid()); + final TimeValue delay = TimeValue.timeValueMillis(expiryDuration + gracePeriodDuration.getMillis()); + // cancel any previous notifications + cancelNotifications(expiryNotifications); + try { + logger.debug("schedule expiry notification after [{}] for license [{}]", delay.toString(), license.uid()); + expiryNotifications.add(threadPool.schedule(delay, executorName(), new LicensingClientNotificationJob())); + } catch (EsRejectedExecutionException ex) { + logger.debug("couldn't schedule expiry notification", ex); + } + } else { + for (InternalLicensee licensee : registeredLicensees) { + licensee.onChange(license, LicenseState.DISABLED); + } + logger.info("license [{}] - expired", license.uid()); + } + if (!license.equals(currentLicense.get())) { + currentLicense.set(license); + // cancel all scheduled event notifications + cancelNotifications(eventNotifications); + // schedule expiry callbacks + for (ExpirationCallback expirationCallback : this.expirationCallbacks) { + final TimeValue delay; + if (expirationCallback.matches(license.expiryDate(), now)) { + expirationCallback.on(license); + TimeValue frequency = expirationCallback.frequency(); + delay = frequency != null ? frequency : expirationCallback.delay(expiryDuration); + } else { + delay = expirationCallback.delay(expiryDuration); + } + if (delay != null) { + eventNotifications.add(threadPool.schedule(delay, executorName(), new EventNotificationJob(expirationCallback))); + } + if (logger.isDebugEnabled()) { + logger.debug("schedule [{}] after [{}]", expirationCallback, delay); + } + } + logger.debug("scheduled expiry callbacks for [{}] expiring after [{}]", license.uid(), + TimeValue.timeValueMillis(expiryDuration)); } - logger.debug("scheduled expiry callbacks for [{}] expiring after [{}]", license.uid(), - TimeValue.timeValueMillis(expiryDuration)); } } @@ -775,10 +779,12 @@ public class LicensesService extends AbstractLifecycleComponent REGISTER_TRIAL_LICENSE_ACTION_NAME, TransportRequest.Empty.INSTANCE, EmptyTransportResponseHandler.INSTANCE_SAME); } - public License getLicense(final LicensesMetaData metaData) { + License getLicense(final LicensesMetaData metaData) { if (metaData != null) { License license = metaData.getLicense(); - if (license != LicensesMetaData.LICENSE_TOMBSTONE) { + if (license == LicensesMetaData.LICENSE_TOMBSTONE) { + return license; + } else { boolean autoGeneratedLicense = License.isAutoGeneratedLicense(license.signature()); if ((autoGeneratedLicense && TrialLicense.verify(license)) || (!autoGeneratedLicense && verifyLicense(license))) { @@ -853,9 +859,11 @@ public class LicensesService extends AbstractLifecycleComponent public void onRemove() { synchronized (this) { - currentLicense = null; - currentLicenseState = null; - licensee.onChange(Licensee.Status.MISSING); + if (currentLicense != null || currentLicenseState != LicenseState.DISABLED) { + currentLicense = null; + currentLicenseState = LicenseState.DISABLED; + licensee.onChange(Licensee.Status.MISSING); + } } } } diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java index 60912e03a95..9081d75aba2 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesManagerServiceTests.java @@ -135,7 +135,7 @@ public class LicensesManagerServiceTests extends ESSingleNodeTestCase { // generate signed licenses - License license = generateSignedLicense(TimeValue.timeValueHours(1)); + License license = generateSignedLicense("gold", TimeValue.timeValueHours(1)); TestUtils.registerAndAckSignedLicenses(licensesService, license, LicensesStatus.VALID); assertBusy(new Runnable() { @Override diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java index 105f001d21f..f63ff611b16 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringLicensee.java @@ -80,7 +80,7 @@ public class MonitoringLicensee extends AbstractLicenseeComponent Date: Thu, 19 May 2016 02:08:33 -0400 Subject: [PATCH 03/16] Split monitoring smoke tests into separate smoke tests There is a race condition between the smoke tests that get run because of the teardown conditions of REST tests. By splitting them, we can avoid the unrealistic scenario/race condition. Original commit: elastic/x-pack-elasticsearch@f95ae0e595b922b77f1933905c738dff549849d9 --- elasticsearch/qa/build.gradle | 2 +- .../build.gradle | 73 +++++++++++-------- .../insufficient-rights/build.gradle | 1 + ...onitoringWithShieldInsufficientRoleIT.java | 61 ++++++++++++++++ .../roles.yml | 12 +-- ...onitoringWithShieldInsufficientRoleIT.java | 36 --------- .../sufficient-rights/build.gradle | 1 + .../smoketest/MonitoringWithShieldIT.java | 12 +-- 8 files changed, 109 insertions(+), 89 deletions(-) create mode 100644 elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle create mode 100644 elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java delete mode 100644 elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java create mode 100644 elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle rename elasticsearch/qa/smoke-test-monitoring-with-shield/{ => sufficient-rights}/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java (76%) diff --git a/elasticsearch/qa/build.gradle b/elasticsearch/qa/build.gradle index 4be011cce50..f9480ba9217 100644 --- a/elasticsearch/qa/build.gradle +++ b/elasticsearch/qa/build.gradle @@ -1,5 +1,5 @@ subprojects { - project.afterEvaluate { + plugins.withType(org.elasticsearch.gradle.test.RestTestPlugin) { // someone figure out what the x-plugins logic should be project.licenseHeaders.enabled = false } diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/build.gradle b/elasticsearch/qa/smoke-test-monitoring-with-shield/build.gradle index 85715ca77ce..5c9b4d832d6 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-shield/build.gradle +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/build.gradle @@ -1,41 +1,50 @@ -apply plugin: 'elasticsearch.rest-test' +subprojects { + apply plugin: 'elasticsearch.rest-test' -dependencies { - testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime') -} + dependencies { + testCompile project(path: ':x-plugins:elasticsearch:x-pack', configuration: 'runtime') + } -// bring in monitoring rest test suite -task copyMonitoringRestTests(type: Copy) { - into project.sourceSets.test.output.resourcesDir - from project(':x-plugins:elasticsearch:x-pack').sourceSets.test.resources.srcDirs - include 'rest-api-spec/test/monitoring/**' -} + // bring in monitoring rest test suite + task copyMonitoringRestTests(type: Copy) { + into project.sourceSets.test.output.resourcesDir + from project(':x-plugins:elasticsearch:x-pack').sourceSets.test.resources.srcDirs + include 'rest-api-spec/test/monitoring/**' + } -integTest { - dependsOn copyMonitoringRestTests + integTest { + dependsOn copyMonitoringRestTests - cluster { - systemProperty 'es.logger.level', 'TRACE' - plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') - setting 'xpack.monitoring.agent.interval', '3s' - extraConfigFile 'x-pack/roles.yml', 'roles.yml' - setupCommand 'setupTestAdminUser', - 'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser' - setupCommand 'setupMonitoredSystemUser', - 'bin/x-pack/users', 'useradd', 'monitored_system', '-p', 'changeme', '-r', 'monitored_system,required_for_test' - setupCommand 'setupPowerlessUser', - 'bin/x-pack/users', 'useradd', 'no_monitored_system', '-p', 'changeme', '-r', 'required_for_test' + cluster { + systemProperty 'es.logger.level', 'TRACE' + plugin 'x-pack', project(':x-plugins:elasticsearch:x-pack') + setting 'xpack.monitoring.agent.interval', '3s' + extraConfigFile 'x-pack/roles.yml', '../roles.yml' + setupCommand 'setupTestAdminUser', + 'bin/x-pack/users', 'useradd', 'test_admin', '-p', 'changeme', '-r', 'superuser' + setupCommand 'setupMonitoredSystemUser', + 'bin/x-pack/users', 'useradd', 'monitoring_system', '-p', 'changeme', '-r', 'monitoring_system,monitoring_without_bulk' + setupCommand 'setupPowerlessUser', + 'bin/x-pack/users', 'useradd', 'not_monitoring_system', '-p', 'changeme', '-r', 'monitoring_without_bulk' - waitCondition = { node, ant -> - File tmpFile = new File(node.cwd, 'wait.success') - ant.get(src: "http://${node.httpUri()}", - dest: tmpFile.toString(), - username: 'test_admin', - password: 'changeme', - ignoreerrors: true, - retries: 10) - return tmpFile.exists() + waitCondition = { node, ant -> + File tmpFile = new File(node.cwd, 'wait.success') + ant.get(src: "http://${node.httpUri()}", + dest: tmpFile.toString(), + username: 'test_admin', + password: 'changeme', + ignoreerrors: true, + retries: 10) + return tmpFile.exists() + } } } } +/** + * Allow {@code integTest} to be invoked on this project to run both Monitoring+Security smoke tests. + */ +task integTest { + dependsOn subprojects.integTest +} + diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle b/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle new file mode 100644 index 00000000000..4b5bd2876f6 --- /dev/null +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle @@ -0,0 +1 @@ +apply plugin: 'elasticsearch.rest-test' \ No newline at end of file diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java b/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java new file mode 100644 index 00000000000..f4879d2a53d --- /dev/null +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.smoketest; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.shield.authc.support.SecuredString; +import org.elasticsearch.test.rest.ESRestTestCase; +import org.elasticsearch.test.rest.RestTestCandidate; +import org.elasticsearch.test.rest.parser.RestTestParseException; + +import java.io.IOException; + +import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue; +import static org.hamcrest.Matchers.containsString; + +public class MonitoringWithShieldInsufficientRoleIT extends ESRestTestCase { + + public MonitoringWithShieldInsufficientRoleIT(@Name("yaml") RestTestCandidate testCandidate) { + super(testCandidate); + } + + @ParametersFactory + public static Iterable parameters() throws IOException, RestTestParseException { + return ESRestTestCase.createParameters(0, 1); + } + + @Override + protected Settings restClientSettings() { + String token = basicAuthHeaderValue("not_monitoring_system", new SecuredString("changeme".toCharArray())); + return Settings.builder() + .put(ThreadContext.PREFIX + ".Authorization", token) + .build(); + } + + @Override + protected Settings restAdminSettings() { + String token = basicAuthHeaderValue("test_admin", new SecuredString("changeme".toCharArray())); + return Settings.builder() + .put(ThreadContext.PREFIX + ".Authorization", token) + .build(); + } + + @Override + public void test() throws IOException { + try { + super.test(); + fail("should have failed because of missing role"); + } catch(AssertionError ae) { + assertThat(ae.getMessage(), containsString("action [cluster:admin/xpack/monitoring/bulk]")); + assertThat(ae.getMessage(), containsString("returned [403 Forbidden]")); + assertThat(ae.getMessage(), containsString("is unauthorized for user [not_monitoring_system]")); + } + } + +} diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/roles.yml b/elasticsearch/qa/smoke-test-monitoring-with-shield/roles.yml index 308a49051b7..e317cb01295 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-shield/roles.yml +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/roles.yml @@ -1,15 +1,7 @@ -admin: - cluster: - - all - indices: - - names: '*' - privileges: - - all - -monitored_system: +monitoring_system: cluster: [ 'cluster:admin/xpack/monitoring/bulk' ] -required_for_test: +monitoring_without_bulk: cluster: [ 'monitor' ] indices: - names: '.monitoring-*' diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java b/elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java deleted file mode 100644 index e08a0e992a1..00000000000 --- a/elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldInsufficientRoleIT.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.smoketest; - -import com.carrotsearch.randomizedtesting.annotations.Name; -import org.elasticsearch.test.rest.RestTestCandidate; - -import java.io.IOException; - -import static org.hamcrest.Matchers.containsString; - -public class MonitoringWithShieldInsufficientRoleIT extends MonitoringWithShieldIT { - - public MonitoringWithShieldInsufficientRoleIT(@Name("yaml") RestTestCandidate testCandidate) { - super(testCandidate); - } - - public void test() throws IOException { - try { - super.test(); - fail("should have failed because of missing role"); - } catch(AssertionError ae) { - assertThat(ae.getMessage(), containsString("action [cluster:admin/xpack/monitoring/bulk]")); - assertThat(ae.getMessage(), containsString("returned [403 Forbidden]")); - assertThat(ae.getMessage(), containsString("is unauthorized for user [no_monitored_system]")); - } - } - - @Override - protected String[] getCredentials() { - return new String[]{"no_monitored_system", "changeme"}; - } -} diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle b/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle new file mode 100644 index 00000000000..4b5bd2876f6 --- /dev/null +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle @@ -0,0 +1 @@ +apply plugin: 'elasticsearch.rest-test' \ No newline at end of file diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java b/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java similarity index 76% rename from elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java rename to elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java index 8c803d543f6..b6f4f47282b 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-shield/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/src/test/java/org/elasticsearch/smoketest/MonitoringWithShieldIT.java @@ -20,9 +20,6 @@ import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basic public class MonitoringWithShieldIT extends ESRestTestCase { - private final static String TEST_ADMIN_USERNAME = "test_admin"; - private final static String TEST_ADMIN_PASSWORD = "changeme"; - public MonitoringWithShieldIT(@Name("yaml") RestTestCandidate testCandidate) { super(testCandidate); } @@ -32,14 +29,9 @@ public class MonitoringWithShieldIT extends ESRestTestCase { return ESRestTestCase.createParameters(0, 1); } - protected String[] getCredentials() { - return new String[]{"monitored_system", "changeme"}; - } - @Override protected Settings restClientSettings() { - String[] creds = getCredentials(); - String token = basicAuthHeaderValue(creds[0], new SecuredString(creds[1].toCharArray())); + String token = basicAuthHeaderValue("monitoring_system", new SecuredString("changeme".toCharArray())); return Settings.builder() .put(ThreadContext.PREFIX + ".Authorization", token) .build(); @@ -47,7 +39,7 @@ public class MonitoringWithShieldIT extends ESRestTestCase { @Override protected Settings restAdminSettings() { - String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecuredString(TEST_ADMIN_PASSWORD.toCharArray())); + String token = basicAuthHeaderValue("test_admin", new SecuredString("changeme".toCharArray())); return Settings.builder() .put(ThreadContext.PREFIX + ".Authorization", token) .build(); From 93ca4db1cef8dd0e7a9b46b529b7b1c93f09604d Mon Sep 17 00:00:00 2001 From: Chris Earle Date: Thu, 19 May 2016 02:20:55 -0400 Subject: [PATCH 04/16] Remove duped plugin application from Gradle script. Original commit: elastic/x-pack-elasticsearch@6745b39c82b8dfe97cf646b924ea5a3fd70eb4da --- .../insufficient-rights/build.gradle | 1 - .../sufficient-rights/build.gradle | 1 - 2 files changed, 2 deletions(-) diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle b/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle index 4b5bd2876f6..e69de29bb2d 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/insufficient-rights/build.gradle @@ -1 +0,0 @@ -apply plugin: 'elasticsearch.rest-test' \ No newline at end of file diff --git a/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle b/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle index 4b5bd2876f6..e69de29bb2d 100644 --- a/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle +++ b/elasticsearch/qa/smoke-test-monitoring-with-shield/sufficient-rights/build.gradle @@ -1 +0,0 @@ -apply plugin: 'elasticsearch.rest-test' \ No newline at end of file From 87c085d857bfc9df76a497d62a67e147dc591e85 Mon Sep 17 00:00:00 2001 From: Chris Earle Date: Thu, 19 May 2016 02:41:03 -0400 Subject: [PATCH 05/16] Better approach to skipping license check for subprojects Original commit: elastic/x-pack-elasticsearch@8624ab08cc1dff614fde11cd2f5053bf36a0edf8 --- elasticsearch/qa/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elasticsearch/qa/build.gradle b/elasticsearch/qa/build.gradle index f9480ba9217..3c9541e6178 100644 --- a/elasticsearch/qa/build.gradle +++ b/elasticsearch/qa/build.gradle @@ -1,5 +1,5 @@ subprojects { - plugins.withType(org.elasticsearch.gradle.test.RestTestPlugin) { + tasks.withType(org.elasticsearch.gradle.precommit.LicenseHeadersTask) { // someone figure out what the x-plugins logic should be project.licenseHeaders.enabled = false } From d6179855bdfb26d37b18c7ad2c6ca0e9526d63fd Mon Sep 17 00:00:00 2001 From: Ali Beyad Date: Thu, 19 May 2016 09:28:53 -0400 Subject: [PATCH 06/16] Renamed AggregatorBuilder to AggregationBuilder, applying the changes to x-plugins. Closes elastic/elasticsearch#2263 Relates elastic/elasticsearch#18377 Original commit: elastic/x-pack-elasticsearch@6d1a69866940aa93969d7bc2c4c9f98add2f0afa --- .../graph/action/GraphExploreRequest.java | 6 ++--- .../action/GraphExploreRequestBuilder.java | 4 +-- .../action/TransportGraphExploreAction.java | 26 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequest.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequest.java index 62c02ed360c..69f7f16de7c 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequest.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequest.java @@ -15,7 +15,7 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.aggregations.bucket.sampler.SamplerAggregatorBuilder; +import org.elasticsearch.search.aggregations.bucket.sampler.SamplerAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.significant.SignificantTerms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator; @@ -39,7 +39,7 @@ public class GraphExploreRequest extends ActionRequest impl private String routing; private TimeValue timeout; - private int sampleSize = SamplerAggregatorBuilder.DEFAULT_SHARD_SAMPLE_SIZE; + private int sampleSize = SamplerAggregationBuilder.DEFAULT_SHARD_SAMPLE_SIZE; private String sampleDiversityField; private int maxDocsPerDiversityValue; private boolean useSignificance = true; @@ -199,7 +199,7 @@ public class GraphExploreRequest extends ActionRequest impl /** * The number of top-matching documents that are considered during each hop (default is - * {@link SamplerAggregatorBuilder#DEFAULT_SHARD_SAMPLE_SIZE} + * {@link SamplerAggregationBuilder#DEFAULT_SHARD_SAMPLE_SIZE} * Very small values (less than 50) may not provide sufficient weight-of-evidence to identify * significant connections between terms. *

Very large values (many thousands) are not recommended with loosely defined queries (fuzzy queries or those diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequestBuilder.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequestBuilder.java index dee78a445dc..9177a12b02d 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequestBuilder.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/GraphExploreRequestBuilder.java @@ -11,7 +11,7 @@ import org.elasticsearch.client.ElasticsearchClient; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.aggregations.bucket.sampler.SamplerAggregatorBuilder; +import org.elasticsearch.search.aggregations.bucket.sampler.SamplerAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.significant.SignificantTerms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator; @@ -138,7 +138,7 @@ public class GraphExploreRequestBuilder extends ActionRequestBuilder Very large values (many thousands) are not recommended with loosely defined queries (fuzzy queries or diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java index 74263e9b500..5323002ea62 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java @@ -29,14 +29,14 @@ import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.license.plugin.core.LicenseUtils; import org.elasticsearch.search.aggregations.AggregationBuilders; -import org.elasticsearch.search.aggregations.AggregatorBuilder; -import org.elasticsearch.search.aggregations.bucket.sampler.DiversifiedAggregatorBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilder; +import org.elasticsearch.search.aggregations.bucket.sampler.DiversifiedAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.sampler.Sampler; import org.elasticsearch.search.aggregations.bucket.significant.SignificantTerms; import org.elasticsearch.search.aggregations.bucket.significant.SignificantTerms.Bucket; -import org.elasticsearch.search.aggregations.bucket.significant.SignificantTermsAggregatorBuilder; +import org.elasticsearch.search.aggregations.bucket.significant.SignificantTermsAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.terms.Terms; -import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregatorBuilder; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.terms.support.IncludeExclude; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.threadpool.ThreadPool; @@ -189,9 +189,9 @@ public class TransportGraphExploreAction extends HandledTransportAction Date: Thu, 12 May 2016 18:31:27 +0200 Subject: [PATCH 07/16] Move unneeded log info messages to debug closes elastic/elasticsearch#2228, elastic/elasticsearch#2227 Original commit: elastic/x-pack-elasticsearch@558751c4248367df561a55d8ec5ec5e2239d4f91 --- elasticsearch/qa/smoke-test-plugins-ssl/build.gradle | 3 +++ .../java/org/elasticsearch/marvel/agent/AgentService.java | 3 ++- .../org/elasticsearch/xpack/watcher/WatcherService.java | 8 ++++---- .../xpack/watcher/trigger/schedule/ScheduleModule.java | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle b/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle index 20b91d468f4..8581f51a63c 100644 --- a/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle +++ b/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle @@ -177,6 +177,9 @@ integTest { setupCommand 'setupMarvelUser', 'bin/x-pack/users', 'useradd', 'monitoring_agent', '-p', 'changeme', '-r', 'remote_monitoring_agent' + // Required to detect that the monitoring agent service has started + systemProperty 'es.logger.level', 'DEBUG' + waitCondition = { node, ant -> // HTTPS check is tricky to do, so we wait for the log file to indicate that the node is started String waitForNodeStartProp = "waitForNodeStart${name}" diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/AgentService.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/AgentService.java index 697c9b0f52a..aeea9b229e7 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/AgentService.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/AgentService.java @@ -120,7 +120,8 @@ public class AgentService extends AbstractLifecycleComponent { @Override protected void doStart() { - logger.info("monitoring service started"); + // Please don't remove this log message since it can be used in integration tests + logger.debug("monitoring service started"); for (Collector collector : collectors) { collector.start(); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherService.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherService.java index bcbb7560590..540d6c4f875 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherService.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherService.java @@ -64,7 +64,7 @@ public class WatcherService extends AbstractComponent { public void start(ClusterState clusterState) throws Exception { if (state.compareAndSet(WatcherState.STOPPED, WatcherState.STARTING)) { try { - logger.info("starting watch service..."); + logger.debug("starting watch service..."); watcherIndexTemplateRegistry.addTemplatesIfMissing(); watchLockService.start(); @@ -74,7 +74,7 @@ public class WatcherService extends AbstractComponent { triggerService.start(watchStore.activeWatches()); state.set(WatcherState.STARTED); - logger.info("watch service has started"); + logger.debug("watch service has started"); } catch (Exception e) { state.set(WatcherState.STOPPED); throw e; @@ -90,7 +90,7 @@ public class WatcherService extends AbstractComponent { public void stop() { if (state.compareAndSet(WatcherState.STARTED, WatcherState.STOPPING)) { - logger.info("stopping watch service..."); + logger.debug("stopping watch service..."); triggerService.stop(); executionService.stop(); try { @@ -100,7 +100,7 @@ public class WatcherService extends AbstractComponent { } watchStore.stop(); state.set(WatcherState.STOPPED); - logger.info("watch service has stopped"); + logger.debug("watch service has stopped"); } else { logger.debug("not stopping watcher, because its state is [{}] while [{}] is expected", state, WatcherState.STARTED); } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/trigger/schedule/ScheduleModule.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/trigger/schedule/ScheduleModule.java index 7c6170fbf93..407362814cf 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/trigger/schedule/ScheduleModule.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/trigger/schedule/ScheduleModule.java @@ -36,7 +36,7 @@ public class ScheduleModule extends AbstractModule { public static Class triggerEngineType(Settings nodeSettings) { Engine engine = Engine.resolve(nodeSettings); - Loggers.getLogger(ScheduleModule.class, nodeSettings).info("using [{}] schedule trigger engine", + Loggers.getLogger(ScheduleModule.class, nodeSettings).debug("using [{}] schedule trigger engine", engine.name().toLowerCase(Locale.ROOT)); return engine.engineType(); } From ded4c2278cbb8b915aa5ffa57eb4e9909c7928a1 Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Thu, 19 May 2016 14:09:49 -0400 Subject: [PATCH 08/16] Remove settings and system properties entanglement This commit removals the usage of system properties as settings from the command scripts and the commands themselves. Relates elastic/elasticsearch#2206 Original commit: elastic/x-pack-elasticsearch@b0a3b895b16708f8c052388293e760caa8d8bee7 --- .../license/licensor/bin/key-pair-generator | 22 +---- .../license/licensor/bin/license-generator | 21 +---- .../license/licensor/bin/verify-license | 21 +---- .../licensor/tools/KeyPairGeneratorTool.java | 19 ++-- .../x-dev-tools/smoke_test_xpack_rc.py | 2 +- elasticsearch/x-pack/bin/x-pack/extension | 40 ++------ .../x-pack/shield/bin/x-pack/syskeygen | 40 ++------ elasticsearch/x-pack/shield/bin/x-pack/users | 40 ++------ .../shield/authc/file/tool/UsersTool.java | 88 ++++++++---------- .../shield/crypto/tool/SystemKeyTool.java | 55 ++++++----- .../authc/file/tool/UsersToolTests.java | 93 ++++++++++--------- .../crypto/tool/SystemKeyToolTests.java | 37 ++++---- .../InstallXPackExtensionCommand.java | 25 ++--- .../extensions/ListXPackExtensionCommand.java | 18 ++-- .../RemoveXPackExtensionCommand.java | 22 +++-- .../xpack/extensions/XPackExtensionCli.java | 15 ++- .../InstallXPackExtensionCommandTests.java | 65 ++++++------- .../ListXPackExtensionCommandTests.java | 46 +++++---- .../RemoveXPackExtensionCommandTests.java | 33 ++++--- .../x-pack/watcher/bin/x-pack/croneval | 31 ++----- 20 files changed, 293 insertions(+), 440 deletions(-) diff --git a/elasticsearch/license/licensor/bin/key-pair-generator b/elasticsearch/license/licensor/bin/key-pair-generator index 08785726269..66eb8cc3c53 100755 --- a/elasticsearch/license/licensor/bin/key-pair-generator +++ b/elasticsearch/license/licensor/bin/key-pair-generator @@ -34,25 +34,5 @@ else JAVA=`which java` fi - -# Parse any long getopt options and put them into properties before calling getopt below -# Be dash compatible to make sure running under ubuntu works -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - -D*=*) - properties="$properties $1" - shift 1; COUNT=$(($COUNT+1)) - ;; - -D*) - properties="$properties $1=$2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -exec "$JAVA" $JAVA_OPTS -Xmx64m -Xms16m $properties -cp "$LICENSE_CLASSPATH" -Des.path.home="`pwd`" org.elasticsearch.license.licensor.tools.KeyPairGeneratorTool "$@" +exec "$JAVA" $JAVA_OPTS -Xmx64m -Xms16m -cp "$LICENSE_CLASSPATH" -Des.path.home="`pwd`" org.elasticsearch.license.licensor.tools.KeyPairGeneratorTool "$@" diff --git a/elasticsearch/license/licensor/bin/license-generator b/elasticsearch/license/licensor/bin/license-generator index 15410bb5a0c..c36ee2aa3e1 100755 --- a/elasticsearch/license/licensor/bin/license-generator +++ b/elasticsearch/license/licensor/bin/license-generator @@ -34,23 +34,4 @@ else JAVA=`which java` fi -# Parse any long getopt options and put them into properties before calling getopt below -# Be dash compatible to make sure running under ubuntu works -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - -D*=*) - properties="$properties $1" - shift 1; COUNT=$(($COUNT+1)) - ;; - -D*) - properties="$properties $1=$2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -exec "$JAVA" $JAVA_OPTS -Xmx64m -Xms16m $properties -cp "$LICENSE_CLASSPATH" -Des.path.home="`pwd`" org.elasticsearch.license.licensor.tools.LicenseGeneratorTool "$@" +exec "$JAVA" $JAVA_OPTS -Xmx64m -Xms16m -cp "$LICENSE_CLASSPATH" -Des.path.home="`pwd`" org.elasticsearch.license.licensor.tools.LicenseGeneratorTool "$@" diff --git a/elasticsearch/license/licensor/bin/verify-license b/elasticsearch/license/licensor/bin/verify-license index 16a12e6089c..cbb3284ae1d 100755 --- a/elasticsearch/license/licensor/bin/verify-license +++ b/elasticsearch/license/licensor/bin/verify-license @@ -34,24 +34,5 @@ else JAVA=`which java` fi -# Parse any long getopt options and put them into properties before calling getopt below -# Be dash compatible to make sure running under ubuntu works -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - -D*=*) - properties="$properties $1" - shift 1; COUNT=$(($COUNT+1)) - ;; - -D*) - properties="$properties $1=$2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -exec "$JAVA" $JAVA_OPTS -Xmx64m -Xms16m $properties -cp "$LICENSE_CLASSPATH" -Des.path.home="`pwd`" org.elasticsearch.license.licensor.tools.LicenseVerificationTool "$@" +exec "$JAVA" $JAVA_OPTS -Xmx64m -Xms16m -cp "$LICENSE_CLASSPATH" -Des.path.home="`pwd`" org.elasticsearch.license.licensor.tools.LicenseVerificationTool "$@" diff --git a/elasticsearch/license/licensor/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java b/elasticsearch/license/licensor/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java index 01e3d580999..f4ba4af817a 100644 --- a/elasticsearch/license/licensor/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java +++ b/elasticsearch/license/licensor/src/main/java/org/elasticsearch/license/licensor/tools/KeyPairGeneratorTool.java @@ -5,22 +5,21 @@ */ package org.elasticsearch.license.licensor.tools; -import java.io.File; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; +import org.elasticsearch.cli.Command; +import org.elasticsearch.cli.ExitCodes; +import org.elasticsearch.cli.Terminal; +import org.elasticsearch.cli.UserError; +import org.elasticsearch.common.SuppressForbidden; +import org.elasticsearch.common.io.PathUtils; + import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; -import joptsimple.OptionSet; -import joptsimple.OptionSpec; -import org.elasticsearch.cli.Command; -import org.elasticsearch.cli.ExitCodes; -import org.elasticsearch.cli.UserError; -import org.elasticsearch.cli.Terminal; -import org.elasticsearch.common.SuppressForbidden; -import org.elasticsearch.common.io.PathUtils; - import static org.elasticsearch.license.core.CryptUtils.writeEncryptedPrivateKey; import static org.elasticsearch.license.core.CryptUtils.writeEncryptedPublicKey; diff --git a/elasticsearch/x-dev-tools/smoke_test_xpack_rc.py b/elasticsearch/x-dev-tools/smoke_test_xpack_rc.py index c6715f9e915..fd4efcd7e2e 100644 --- a/elasticsearch/x-dev-tools/smoke_test_xpack_rc.py +++ b/elasticsearch/x-dev-tools/smoke_test_xpack_rc.py @@ -112,7 +112,7 @@ def smoke_test_release(release, files, expected_hash): print(' Starting elasticsearch daemon from [%s]' % es_dir) try: - run('%s; %s -Ees.node.name=smoke_tester -Ees.cluster.name=prepare_release -Ees.script.inline=true -Ees.script.stored=true -Ees.repositories.url.allowed_urls=http://snapshot.test* %s -Ees.pidfile=%s -Ees.node.portsfile=true' + run('%s; %s -Enode.name=smoke_tester -Ecluster.name=prepare_release -Escript.inline=true -Escript.stored=true -Erepositories.url.allowed_urls=http://snapshot.test* %s -Epidfile=%s -Enode.portsfile=true' % (java_exe(), es_run_path, '-d', os.path.join(es_dir, 'es-smoke.pid'))) if not wait_for_node_startup(es_dir, headers=headers): print("elasticsearch logs:") diff --git a/elasticsearch/x-pack/bin/x-pack/extension b/elasticsearch/x-pack/bin/x-pack/extension index db00c964d8b..505559d0bcc 100755 --- a/elasticsearch/x-pack/bin/x-pack/extension +++ b/elasticsearch/x-pack/bin/x-pack/extension @@ -70,38 +70,6 @@ elif [ -f "/etc/default/elasticsearch" ]; then . "/etc/default/elasticsearch" fi -# Parse any long getopt options and put them into properties before calling getopt below -# Be dash compatible to make sure running under ubuntu works -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - --*=*) properties="$properties -Des.${1#--}" - shift 1; COUNT=$(($COUNT+1)) - ;; - --*) properties="$properties -Des.${1#--}=$2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -# check if properties already has a config file or config dir -if [ -e "$CONF_DIR" ]; then - case "$properties" in - *-Des.default.path.conf=*) ;; - *) - if [ ! -d "$CONF_DIR/x-pack" ]; then - echo "ERROR: The configuration directory [$CONF_DIR/x-pack] does not exist. The extension tool expects security configuration files in that location." - echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/x-pack] exists, please copy the 'x-pack' directory to [$CONF_DIR]" - exit 1 - fi - properties="$properties -Des.default.path.conf=$CONF_DIR" - ;; - esac -fi - export HOSTNAME=`hostname -s` # include x-pack jars in classpath @@ -113,8 +81,14 @@ if [ ! -z "$CONF_FILE" ]; then exit 1 fi +declare -a args=("$@") + +if [ -e "$CONF_DIR" ]; then + args=("${args[@]}" -Edefault.path.conf="$CONF_DIR") +fi + cd "$ES_HOME" > /dev/null -"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" $properties org.elasticsearch.xpack.extensions.XPackExtensionCli "$@" +"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.extensions.XPackExtensionCli "${args[@]}" status=$? cd - > /dev/null exit $status diff --git a/elasticsearch/x-pack/shield/bin/x-pack/syskeygen b/elasticsearch/x-pack/shield/bin/x-pack/syskeygen index 2c9d2a0766c..aaf2da9ab8f 100755 --- a/elasticsearch/x-pack/shield/bin/x-pack/syskeygen +++ b/elasticsearch/x-pack/shield/bin/x-pack/syskeygen @@ -70,38 +70,6 @@ elif [ -f "/etc/default/elasticsearch" ]; then . "/etc/default/elasticsearch" fi -# Parse any long getopt options and put them into properties before calling getopt below -# Be dash compatible to make sure running under ubuntu works -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - --*=*) properties="$properties -Des.${1#--}" - shift 1; COUNT=$(($COUNT+1)) - ;; - --*) properties="$properties -Des.${1#--}=$2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -# check if properties already has a config file or config dir -if [ -e "$CONF_DIR" ]; then - case "$properties" in - *-Des.default.path.conf=*) ;; - *) - if [ ! -d "$CONF_DIR/x-pack" ]; then - echo "ERROR: The configuration directory [$CONF_DIR/x-pack] does not exist. The syskeygen tool expects security configuration files in that location." - echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/x-pack] exists, please copy the 'x-pack' directory to [$CONF_DIR]" - exit 1 - fi - properties="$properties -Des.default.path.conf=$CONF_DIR" - ;; - esac -fi - export HOSTNAME=`hostname -s` # include shield jars in classpath @@ -121,8 +89,14 @@ if [ ! -z "$CONF_FILE" ]; then exit 1 fi +declare -a args=("$@") + +if [ -e "$CONF_DIR" ]; then + args=("${args[@]}" -Edefault.path.conf="$CONF_DIR") +fi + cd "$ES_HOME" > /dev/null -"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" $properties org.elasticsearch.shield.crypto.tool.SystemKeyTool "$@" +"$JAVA" $ES_JAVA_OPTS -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" org.elasticsearch.shield.crypto.tool.SystemKeyTool $properties "{args[@]}" status=$? cd - > /dev/null exit $status diff --git a/elasticsearch/x-pack/shield/bin/x-pack/users b/elasticsearch/x-pack/shield/bin/x-pack/users index 67c9f150272..8efde509c3e 100755 --- a/elasticsearch/x-pack/shield/bin/x-pack/users +++ b/elasticsearch/x-pack/shield/bin/x-pack/users @@ -70,38 +70,6 @@ elif [ -f "/etc/default/elasticsearch" ]; then . "/etc/default/elasticsearch" fi -# Parse any long getopt options and put them into properties before calling getopt below -# Be dash compatible to make sure running under ubuntu works -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - --*=*) properties="$properties -Des.${1#--}" - shift 1; COUNT=$(($COUNT+1)) - ;; - --*) properties="$properties -Des.${1#--}=$2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -# check if properties already has a config file or config dir -if [ -e "$CONF_DIR" ]; then - case "$properties" in - *-Des.default.path.conf=*) ;; - *) - if [ ! -d "$CONF_DIR/x-pack" ]; then - echo "ERROR: The configuration directory [$CONF_DIR/x-pack] does not exist. The users tool expects security configuration files in that location." - echo "The plugin may not have been installed with the correct configuration path. If [$ES_HOME/config/x-pack] exists, please copy the 'x-pack' directory to [$CONF_DIR]" - exit 1 - fi - properties="$properties -Des.default.path.conf=$CONF_DIR" - ;; - esac -fi - export HOSTNAME=`hostname -s` # include shield jars in classpath @@ -121,8 +89,14 @@ if [ ! -z "$CONF_FILE" ]; then exit 1 fi +declare -a args=("$@") + +if [ -e "$CONF_DIR" ]; then + args=("${args[@]}" -Edefault.path.conf="$CONF_DIR") +fi + cd "$ES_HOME" > /dev/null -"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" $properties org.elasticsearch.shield.authc.file.tool.UsersTool "$@" +"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.shield.authc.file.tool.UsersTool "${args[@]}" status=$? cd - > /dev/null exit $status diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/tool/UsersTool.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/tool/UsersTool.java index 0dc39b6ddad..f9a54452358 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/tool/UsersTool.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/tool/UsersTool.java @@ -5,26 +5,14 @@ */ package org.elasticsearch.shield.authc.file.tool; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - import joptsimple.OptionSet; import joptsimple.OptionSpec; -import org.elasticsearch.cli.Command; import org.elasticsearch.cli.ExitCodes; import org.elasticsearch.cli.MultiCommand; +import org.elasticsearch.cli.SettingCommand; +import org.elasticsearch.cli.Terminal; import org.elasticsearch.cli.UserError; import org.elasticsearch.common.Strings; -import org.elasticsearch.cli.Terminal; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.env.Environment; @@ -40,32 +28,41 @@ import org.elasticsearch.shield.support.FileAttributesChecker; import org.elasticsearch.shield.support.Validation; import org.elasticsearch.shield.support.Validation.Users; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + public class UsersTool extends MultiCommand { public static void main(String[] args) throws Exception { - Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, Terminal.DEFAULT); - exit(new UsersTool(env).main(args, Terminal.DEFAULT)); + exit(new UsersTool().main(args, Terminal.DEFAULT)); } - UsersTool(Environment env) { + UsersTool() { super("Manages elasticsearch native users"); - subcommands.put("useradd", new AddUserCommand(env)); - subcommands.put("userdel", new DeleteUserCommand(env)); - subcommands.put("passwd", new PasswordCommand(env)); - subcommands.put("roles", new RolesCommand(env)); - subcommands.put("list", new ListCommand(env)); + subcommands.put("useradd", new AddUserCommand()); + subcommands.put("userdel", new DeleteUserCommand()); + subcommands.put("passwd", new PasswordCommand()); + subcommands.put("roles", new RolesCommand()); + subcommands.put("list", new ListCommand()); } - static class AddUserCommand extends Command { + static class AddUserCommand extends SettingCommand { - private final Environment env; private final OptionSpec passwordOption; private final OptionSpec rolesOption; private final OptionSpec arguments; - AddUserCommand(Environment env) { + AddUserCommand() { super("Adds a native user"); - this.env = env; this.passwordOption = parser.acceptsAll(Arrays.asList("p", "password"), "The user password") .withRequiredArg(); @@ -87,7 +84,7 @@ public class UsersTool extends MultiCommand { } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { String username = parseUsername(arguments.values(options)); Validation.Error validationError = Users.validateUsername(username); if (validationError != null) { @@ -95,6 +92,7 @@ public class UsersTool extends MultiCommand { } char[] password = parsePassword(terminal, passwordOption.value(options)); + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); String[] roles = parseRoles(terminal, env, rolesOption.value(options)); Settings fileSettings = Realms.fileRealmSettings(env.settings()); @@ -120,14 +118,12 @@ public class UsersTool extends MultiCommand { } } - static class DeleteUserCommand extends Command { + static class DeleteUserCommand extends SettingCommand { - private final Environment env; private final OptionSpec arguments; - DeleteUserCommand(Environment env) { + DeleteUserCommand() { super("Deletes a file based user"); - this.env = env; this.arguments = parser.nonOptions("username"); } @@ -143,8 +139,9 @@ public class UsersTool extends MultiCommand { } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { String username = parseUsername(arguments.values(options)); + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); Settings fileSettings = Realms.fileRealmSettings(env.settings()); Path passwordFile = FileUserPasswdStore.resolveFile(fileSettings, env); Path rolesFile = FileUserRolesStore.resolveFile(fileSettings, env); @@ -173,15 +170,13 @@ public class UsersTool extends MultiCommand { } } - static class PasswordCommand extends Command { + static class PasswordCommand extends SettingCommand { - private final Environment env; private final OptionSpec passwordOption; private final OptionSpec arguments; - PasswordCommand(Environment env) { + PasswordCommand() { super("Changes the password of an existing file based user"); - this.env = env; this.passwordOption = parser.acceptsAll(Arrays.asList("p", "password"), "The user password") .withRequiredArg(); @@ -200,10 +195,11 @@ public class UsersTool extends MultiCommand { } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { String username = parseUsername(arguments.values(options)); char[] password = parsePassword(terminal, passwordOption.value(options)); + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); Settings fileSettings = Realms.fileRealmSettings(env.settings()); Path file = FileUserPasswdStore.resolveFile(fileSettings, env); FileAttributesChecker attributesChecker = new FileAttributesChecker(file); @@ -218,16 +214,14 @@ public class UsersTool extends MultiCommand { } } - static class RolesCommand extends Command { + static class RolesCommand extends SettingCommand { - private final Environment env; private final OptionSpec addOption; private final OptionSpec removeOption; private final OptionSpec arguments; - RolesCommand(Environment env) { + RolesCommand() { super("Edit roles of an existing user"); - this.env = env; this.addOption = parser.acceptsAll(Arrays.asList("a", "add"), "Adds supplied roles to the specified user") .withRequiredArg().defaultsTo(""); @@ -246,8 +240,9 @@ public class UsersTool extends MultiCommand { } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { String username = parseUsername(arguments.values(options)); + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); String[] addRoles = parseRoles(terminal, env, addOption.value(options)); String[] removeRoles = parseRoles(terminal, env, removeOption.value(options)); @@ -290,14 +285,12 @@ public class UsersTool extends MultiCommand { } } - static class ListCommand extends Command { + static class ListCommand extends SettingCommand { - private final Environment env; private final OptionSpec arguments; - ListCommand(Environment env) { + ListCommand() { super("List existing file based users and their corresponding roles"); - this.env = env; this.arguments = parser.nonOptions("username"); } @@ -308,11 +301,12 @@ public class UsersTool extends MultiCommand { } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { String username = null; if (options.has(arguments)) { username = arguments.value(options); } + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); listUsersAndRoles(terminal, env, username); } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/crypto/tool/SystemKeyTool.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/crypto/tool/SystemKeyTool.java index 8973afe7f22..15eb07390ab 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/crypto/tool/SystemKeyTool.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/crypto/tool/SystemKeyTool.java @@ -5,21 +5,14 @@ */ package org.elasticsearch.shield.crypto.tool; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.nio.file.attribute.PosixFileAttributeView; -import java.nio.file.attribute.PosixFilePermission; -import java.util.List; -import java.util.Locale; -import java.util.Set; - import joptsimple.OptionSet; import joptsimple.OptionSpec; +import joptsimple.util.KeyValuePair; import org.elasticsearch.cli.Command; import org.elasticsearch.cli.ExitCodes; -import org.elasticsearch.cli.UserError; +import org.elasticsearch.cli.SettingCommand; import org.elasticsearch.cli.Terminal; +import org.elasticsearch.cli.UserError; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.settings.Settings; @@ -28,28 +21,47 @@ import org.elasticsearch.env.Environment; import org.elasticsearch.node.internal.InternalSettingsPreparer; import org.elasticsearch.shield.crypto.InternalCryptoService; -public class SystemKeyTool extends Command { +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.PosixFileAttributeView; +import java.nio.file.attribute.PosixFilePermission; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +public class SystemKeyTool extends SettingCommand { + + private final OptionSpec arguments; + + SystemKeyTool() { + super("system key tool"); + arguments = parser.nonOptions("key path"); + } public static final Set PERMISSION_OWNER_READ_WRITE = Sets.newHashSet(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE); public static void main(String[] args) throws Exception { - Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, Terminal.DEFAULT); - exit(new SystemKeyTool(env).main(args, Terminal.DEFAULT)); + final SystemKeyTool tool = new SystemKeyTool(); + int status = main(tool, args, Terminal.DEFAULT); + if (status != ExitCodes.OK) { + exit(status); + } } - private final Environment env; - private final OptionSpec arguments; - - public SystemKeyTool(Environment env) { - super("Generates the system key"); - this.env = env; - this.arguments = parser.nonOptions("key path"); + static int main(SystemKeyTool tool, String[] args, Terminal terminal) throws Exception { + return tool.main(args, terminal); } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { final Path keyPath; + + final Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); + if (options.hasArgument(arguments)) { List args = arguments.values(options); if (args.size() > 1) { @@ -79,4 +91,5 @@ public class SystemKeyTool extends Command { private static Path parsePath(String path) { return PathUtils.get(path); } + } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/tool/UsersToolTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/tool/UsersToolTests.java index afd8bb601ee..8e18018dac6 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/tool/UsersToolTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/tool/UsersToolTests.java @@ -5,16 +5,6 @@ */ package org.elasticsearch.shield.authc.file.tool; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.FileSystem; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import org.apache.lucene.util.IOUtils; @@ -35,17 +25,28 @@ import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + public class UsersToolTests extends CommandTestCase { // the mock filesystem we use so permissions/users/groups can be modified static FileSystem jimfs; + String pathHomeParameter; + String fileTypeParameter; // the config dir for each test to use Path confDir; // settings used to create an Environment for tools - Settings.Builder settingsBuilder; - + Settings settings; @BeforeClass public static void setupJimfs() throws IOException { @@ -78,9 +79,13 @@ public class UsersToolTests extends CommandTestCase { "test_r2:", " cluster: all" ), StandardCharsets.UTF_8); - settingsBuilder = Settings.builder() - .put("path.home", homeDir) - .put("xpack.security.authc.realms.file.type", "file"); + settings = + Settings.builder() + .put("path.home", homeDir) + .put("xpack.security.authc.realms.file.type", "file") + .build(); + pathHomeParameter = "-Epath.home=" + homeDir; + fileTypeParameter = "-Expack.security.authc.realms.file.type=file"; } @AfterClass @@ -92,7 +97,7 @@ public class UsersToolTests extends CommandTestCase { @Override protected Command newCommand() { - return new UsersTool(new Environment(settingsBuilder.build())); + return new UsersTool(); } /** checks the user exists with the given password */ @@ -219,7 +224,7 @@ public class UsersToolTests extends CommandTestCase { } public void testParseUnknownRole() throws Exception { - UsersTool.parseRoles(terminal, new Environment(settingsBuilder.build()), "test_r1,r2,r3"); + UsersTool.parseRoles(terminal, new Environment(settings), "test_r1,r2,r3"); String output = terminal.getOutput(); assertTrue(output, output.contains("The following roles [r2,r3] are not in the [")); } @@ -227,21 +232,21 @@ public class UsersToolTests extends CommandTestCase { public void testParseReservedRole() throws Exception { final String reservedRoleName = randomFrom(ReservedRolesStore.names().toArray(Strings.EMPTY_ARRAY)); String rolesArg = randomBoolean() ? "test_r1," + reservedRoleName : reservedRoleName; - UsersTool.parseRoles(terminal, new Environment(settingsBuilder.build()), rolesArg); + UsersTool.parseRoles(terminal, new Environment(settings), rolesArg); String output = terminal.getOutput(); assertTrue(output, output.isEmpty()); } public void testParseInvalidRole() throws Exception { UserError e = expectThrows(UserError.class, () -> { - UsersTool.parseRoles(terminal, new Environment(settingsBuilder.build()), "$345"); + UsersTool.parseRoles(terminal, new Environment(settings), "$345"); }); assertEquals(ExitCodes.DATA_ERROR, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("Invalid role [$345]")); } public void testParseMultipleRoles() throws Exception { - String[] roles = UsersTool.parseRoles(terminal, new Environment(settingsBuilder.build()), "test_r1,test_r2"); + String[] roles = UsersTool.parseRoles(terminal, new Environment(settings), "test_r1,test_r2"); assertEquals(Objects.toString(roles), 2, roles.length); assertEquals("test_r1", roles[0]); assertEquals("test_r2", roles[1]); @@ -250,18 +255,18 @@ public class UsersToolTests extends CommandTestCase { public void testUseraddNoPassword() throws Exception { terminal.addSecretInput("changeme"); terminal.addSecretInput("changeme"); - execute("useradd", "username"); + execute("useradd", pathHomeParameter, fileTypeParameter, "username"); assertUser("username", "changeme"); } public void testUseraddPasswordOption() throws Exception { - execute("useradd", "username", "-p", "changeme"); + execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme"); assertUser("username", "changeme"); } public void testUseraddUserExists() throws Exception { UserError e = expectThrows(UserError.class, () -> { - execute("useradd", "existing_user", "-p", "changeme"); + execute("useradd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", "changeme"); }); assertEquals(ExitCodes.CODE_ERROR, e.exitCode); assertEquals("User [existing_user] already exists", e.getMessage()); @@ -270,27 +275,27 @@ public class UsersToolTests extends CommandTestCase { public void testUseraddNoRoles() throws Exception { Files.delete(confDir.resolve("users_roles")); Files.createFile(confDir.resolve("users_roles")); - execute("useradd", "username", "-p", "changeme"); + execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme"); List lines = Files.readAllLines(confDir.resolve("users_roles"), StandardCharsets.UTF_8); assertTrue(lines.toString(), lines.isEmpty()); } public void testUserdelUnknownUser() throws Exception { UserError e = expectThrows(UserError.class, () -> { - execute("userdel", "unknown"); + execute("userdel", pathHomeParameter, fileTypeParameter, "unknown"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); } public void testUserdel() throws Exception { - execute("userdel", "existing_user"); + execute("userdel", pathHomeParameter, fileTypeParameter, "existing_user"); assertNoUser("existing_user"); } public void testPasswdUnknownUser() throws Exception { UserError e = expectThrows(UserError.class, () -> { - execute("passwd", "unknown", "-p", "changeme"); + execute("passwd", pathHomeParameter, fileTypeParameter, "unknown", "-p", "changeme"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); @@ -299,64 +304,64 @@ public class UsersToolTests extends CommandTestCase { public void testPasswdNoPasswordOption() throws Exception { terminal.addSecretInput("newpassword"); terminal.addSecretInput("newpassword"); - execute("passwd", "existing_user"); + execute("passwd", pathHomeParameter, fileTypeParameter, "existing_user"); assertUser("existing_user", "newpassword"); assertRole("test_admin", "existing_user", "existing_user2"); // roles unchanged } public void testPasswd() throws Exception { - execute("passwd", "existing_user", "-p", "newpassword"); + execute("passwd", pathHomeParameter, fileTypeParameter, "existing_user", "-p", "newpassword"); assertUser("existing_user", "newpassword"); assertRole("test_admin", "existing_user"); // roles unchanged } public void testRolesUnknownUser() throws Exception { UserError e = expectThrows(UserError.class, () -> { - execute("roles", "unknown"); + execute("roles", pathHomeParameter, fileTypeParameter, "unknown"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); } public void testRolesAdd() throws Exception { - execute("roles", "existing_user", "-a", "test_r1"); + execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-a", "test_r1"); assertRole("test_admin", "existing_user"); assertRole("test_r1", "existing_user"); } public void testRolesRemove() throws Exception { - execute("roles", "existing_user", "-r", "test_admin"); + execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin"); assertRole("test_admin", "existing_user2"); } public void testRolesAddAndRemove() throws Exception { - execute("roles", "existing_user", "-a", "test_r1", "-r", "test_admin"); + execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-a", "test_r1", "-r", "test_admin"); assertRole("test_admin", "existing_user2"); assertRole("test_r1", "existing_user"); } public void testRolesRemoveLeavesExisting() throws Exception { - execute("useradd", "username", "-p", "changeme", "-r", "test_admin"); - execute("roles", "existing_user", "-r", "test_admin"); + execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme", "-r", "test_admin"); + execute("roles", pathHomeParameter, fileTypeParameter, "existing_user", "-r", "test_admin"); assertRole("test_admin", "username"); } public void testRolesNoAddOrRemove() throws Exception { - String output = execute("roles", "existing_user"); + String output = execute("roles", pathHomeParameter, fileTypeParameter, "existing_user"); assertTrue(output, output.contains("existing_user")); assertTrue(output, output.contains("test_admin")); } public void testListUnknownUser() throws Exception { UserError e = expectThrows(UserError.class, () -> { - execute("list", "unknown"); + execute("list", pathHomeParameter, fileTypeParameter, "unknown"); }); assertEquals(ExitCodes.NO_USER, e.exitCode); assertTrue(e.getMessage(), e.getMessage().contains("User [unknown] doesn't exist")); } public void testListAllUsers() throws Exception { - String output = execute("list"); + String output = execute("list", pathHomeParameter, fileTypeParameter); assertTrue(output, output.contains("existing_user")); assertTrue(output, output.contains("test_admin")); assertTrue(output, output.contains("existing_user2")); @@ -367,7 +372,7 @@ public class UsersToolTests extends CommandTestCase { } public void testListSingleUser() throws Exception { - String output = execute("list", "existing_user"); + String output = execute("list", pathHomeParameter, fileTypeParameter, "existing_user"); assertTrue(output, output.contains("existing_user")); assertTrue(output, output.contains("test_admin")); assertFalse(output, output.contains("existing_user2")); @@ -378,8 +383,8 @@ public class UsersToolTests extends CommandTestCase { } public void testListUnknownRoles() throws Exception { - execute("useradd", "username", "-p", "changeme", "-r", "test_r1,r2,r3"); - String output = execute("list", "username"); + execute("useradd", pathHomeParameter, fileTypeParameter, "username", "-p", "changeme", "-r", "test_r1,r2,r3"); + String output = execute("list", pathHomeParameter, fileTypeParameter, "username"); assertTrue(output, output.contains("username")); assertTrue(output, output.contains("r2*,r3*,test_r1")); } @@ -389,14 +394,14 @@ public class UsersToolTests extends CommandTestCase { Files.createFile(confDir.resolve("users")); Files.delete(confDir.resolve("users_roles")); Files.createFile(confDir.resolve("users_roles")); - String output = execute("list"); + String output = execute("list", pathHomeParameter, fileTypeParameter); assertTrue(output, output.contains("No users found")); } public void testListUserWithoutRoles() throws Exception { - String output = execute("list", "existing_user3"); + String output = execute("list", pathHomeParameter, fileTypeParameter, "existing_user3"); assertTrue(output, output.contains("existing_user3")); - output = execute("list"); + output = execute("list", pathHomeParameter, fileTypeParameter); assertTrue(output, output.contains("existing_user3")); // output should not contain '*' which indicates unknown role diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/crypto/tool/SystemKeyToolTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/crypto/tool/SystemKeyToolTests.java index 8065e097250..636605c18fd 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/crypto/tool/SystemKeyToolTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/crypto/tool/SystemKeyToolTests.java @@ -7,12 +7,12 @@ package org.elasticsearch.shield.crypto.tool; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; +import org.apache.lucene.util.IOUtils; import org.elasticsearch.cli.Command; import org.elasticsearch.cli.CommandTestCase; import org.elasticsearch.common.io.PathUtilsForTesting; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; import org.elasticsearch.shield.crypto.InternalCryptoService; +import org.junit.After; import java.nio.file.FileSystem; import java.nio.file.Files; @@ -23,32 +23,33 @@ import java.util.Set; public class SystemKeyToolTests extends CommandTestCase { private FileSystem jimfs; - private Settings.Builder settingsBuilder; - private Path homeDir; - private void initFileSystem(boolean needsPosix) throws Exception { + private Path initFileSystem(boolean needsPosix) throws Exception { String view = needsPosix ? "posix" : randomFrom("basic", "posix"); Configuration conf = Configuration.unix().toBuilder().setAttributeViews(view).build(); jimfs = Jimfs.newFileSystem(conf); PathUtilsForTesting.installMock(jimfs); - homeDir = jimfs.getPath("eshome"); + return jimfs.getPath("eshome"); + } - settingsBuilder = Settings.builder() - .put(Environment.PATH_HOME_SETTING.getKey(), homeDir); + @After + public void tearDown() throws Exception { + IOUtils.close(jimfs); + super.tearDown(); } @Override protected Command newCommand() { - return new SystemKeyTool(new Environment(settingsBuilder.build())); + return new SystemKeyTool(); } public void testGenerate() throws Exception { - initFileSystem(true); + final Path homeDir = initFileSystem(true); Path path = jimfs.getPath(randomAsciiOfLength(10)).resolve("key"); Files.createDirectory(path.getParent()); - execute(path.toString()); + execute("-Epath.home=" + homeDir, path.toString()); byte[] bytes = Files.readAllBytes(path); // TODO: maybe we should actually check the key is...i dunno...valid? assertEquals(InternalCryptoService.KEY_SIZE / 8, bytes.length); @@ -60,35 +61,35 @@ public class SystemKeyToolTests extends CommandTestCase { } public void testGeneratePathInSettings() throws Exception { - initFileSystem(false); + final Path homeDir = initFileSystem(false); Path path = jimfs.getPath(randomAsciiOfLength(10)).resolve("key"); Files.createDirectories(path.getParent()); - settingsBuilder.put(InternalCryptoService.FILE_SETTING.getKey(), path.toAbsolutePath().toString()); - execute(); + execute("-Epath.home=" + homeDir.toString(), "-Expack.security.system_key.file=" + path.toAbsolutePath().toString()); byte[] bytes = Files.readAllBytes(path); assertEquals(InternalCryptoService.KEY_SIZE / 8, bytes.length); } public void testGenerateDefaultPath() throws Exception { - initFileSystem(false); + final Path homeDir = initFileSystem(false); Path keyPath = homeDir.resolve("config/x-pack/system_key"); Files.createDirectories(keyPath.getParent()); - execute(); + execute("-Epath.home=" + homeDir.toString()); byte[] bytes = Files.readAllBytes(keyPath); assertEquals(InternalCryptoService.KEY_SIZE / 8, bytes.length); } public void testThatSystemKeyMayOnlyBeReadByOwner() throws Exception { - initFileSystem(true); + final Path homeDir = initFileSystem(true); Path path = jimfs.getPath(randomAsciiOfLength(10)).resolve("key"); Files.createDirectories(path.getParent()); - execute(path.toString()); + execute("-Epath.home=" + homeDir, path.toString()); Set perms = Files.getPosixFilePermissions(path); assertTrue(perms.toString(), perms.contains(PosixFilePermission.OWNER_READ)); assertTrue(perms.toString(), perms.contains(PosixFilePermission.OWNER_WRITE)); assertEquals(perms.toString(), 2, perms.size()); } + } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommand.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommand.java index 3f97ea13546..cf161e65012 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommand.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommand.java @@ -8,17 +8,18 @@ package org.elasticsearch.xpack.extensions; import joptsimple.OptionSet; import joptsimple.OptionSpec; import org.apache.lucene.util.IOUtils; - import org.elasticsearch.bootstrap.JarHell; -import org.elasticsearch.cli.Command; import org.elasticsearch.cli.ExitCodes; +import org.elasticsearch.cli.SettingCommand; import org.elasticsearch.cli.Terminal; import org.elasticsearch.cli.UserError; import org.elasticsearch.common.io.FileSystemUtils; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.node.internal.InternalSettingsPreparer; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLDecoder; @@ -26,13 +27,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; -import java.util.List; import java.util.Arrays; +import java.util.List; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import static org.elasticsearch.xpack.XPackPlugin.resolveXPackExtensionsFile; import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE; +import static org.elasticsearch.xpack.XPackPlugin.resolveXPackExtensionsFile; /** * A command for the extension cli to install an extension into x-pack. @@ -49,22 +51,20 @@ import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE; *

  • Jar hell does not exist, either between the extension's own jars or with the parent classloader (elasticsearch + x-pack)
  • * */ -class InstallXPackExtensionCommand extends Command { +class InstallXPackExtensionCommand extends SettingCommand { - private final Environment env; private final OptionSpec batchOption; private final OptionSpec arguments; - InstallXPackExtensionCommand(Environment env) { + InstallXPackExtensionCommand() { super("Install a plugin"); - this.env = env; this.batchOption = parser.acceptsAll(Arrays.asList("b", "batch"), "Enable batch mode explicitly, automatic confirmation of security permission"); this.arguments = parser.nonOptions("plugin id"); } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { // TODO: in jopt-simple 5.0 we can enforce a min/max number of positional args List args = arguments.values(options); if (args.size() != 1) { @@ -72,12 +72,13 @@ class InstallXPackExtensionCommand extends Command { } String extensionURL = args.get(0); boolean isBatch = options.has(batchOption) || System.console() == null; - execute(terminal, extensionURL, isBatch); + execute(terminal, extensionURL, isBatch, settings); } // pkg private for testing - void execute(Terminal terminal, String extensionId, boolean isBatch) throws Exception { + void execute(Terminal terminal, String extensionId, boolean isBatch, Map properties) throws Exception { + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, properties); if (Files.exists(resolveXPackExtensionsFile(env)) == false) { terminal.println("xpack extensions directory [" + resolveXPackExtensionsFile(env) + "] does not exist. Creating..."); Files.createDirectories(resolveXPackExtensionsFile(env)); diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommand.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommand.java index ccf7768fb95..204c7b2eebc 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommand.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommand.java @@ -6,32 +6,33 @@ package org.elasticsearch.xpack.extensions; import joptsimple.OptionSet; - -import org.elasticsearch.cli.Command; +import org.elasticsearch.cli.SettingCommand; import org.elasticsearch.cli.Terminal; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.node.internal.InternalSettingsPreparer; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; -import static org.elasticsearch.xpack.XPackPlugin.resolveXPackExtensionsFile; import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE; +import static org.elasticsearch.xpack.XPackPlugin.resolveXPackExtensionsFile; /** * A command for the extension cli to list extensions installed in x-pack. */ -class ListXPackExtensionCommand extends Command { - private final Environment env; +class ListXPackExtensionCommand extends SettingCommand { - ListXPackExtensionCommand(Environment env) { + ListXPackExtensionCommand() { super("Lists installed x-pack extensions"); - this.env = env; } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); if (Files.exists(resolveXPackExtensionsFile(env)) == false) { throw new IOException("Extensions directory missing: " + resolveXPackExtensionsFile(env)); } @@ -43,4 +44,5 @@ class ListXPackExtensionCommand extends Command { } } } + } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommand.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommand.java index b700a8d62ad..1da0e61f863 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommand.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommand.java @@ -7,51 +7,53 @@ package org.elasticsearch.xpack.extensions; import joptsimple.OptionSet; import joptsimple.OptionSpec; - import org.apache.lucene.util.IOUtils; -import org.elasticsearch.cli.Command; import org.elasticsearch.cli.ExitCodes; +import org.elasticsearch.cli.SettingCommand; import org.elasticsearch.cli.Terminal; import org.elasticsearch.cli.UserError; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.node.internal.InternalSettingsPreparer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; +import java.util.Map; -import static org.elasticsearch.xpack.XPackPlugin.resolveXPackExtensionsFile; import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE; +import static org.elasticsearch.xpack.XPackPlugin.resolveXPackExtensionsFile; /** * A command for the extension cli to remove an extension from x-pack. */ -class RemoveXPackExtensionCommand extends Command { - private final Environment env; +class RemoveXPackExtensionCommand extends SettingCommand { private final OptionSpec arguments; - RemoveXPackExtensionCommand(Environment env) { + RemoveXPackExtensionCommand() { super("Removes an extension from x-pack"); - this.env = env; this.arguments = parser.nonOptions("extension name"); } @Override - protected void execute(Terminal terminal, OptionSet options) throws Exception { + protected void execute(Terminal terminal, OptionSet options, Map settings) throws Exception { + // TODO: in jopt-simple 5.0 we can enforce a min/max number of positional args List args = arguments.values(options); if (args.size() != 1) { throw new UserError(ExitCodes.USAGE, "Must supply a single extension id argument"); } - execute(terminal, args.get(0)); + execute(terminal, args.get(0), settings); } // pkg private for testing - void execute(Terminal terminal, String extensionName) throws Exception { + void execute(Terminal terminal, String extensionName, Map settings) throws Exception { terminal.println("-> Removing " + Strings.coalesceToEmpty(extensionName) + "..."); + Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings); Path extensionDir = resolveXPackExtensionsFile(env).resolve(extensionName); if (Files.exists(extensionDir) == false) { throw new UserError(ExitCodes.USAGE, diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/XPackExtensionCli.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/XPackExtensionCli.java index f18d3db3a02..c17ae66e589 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/XPackExtensionCli.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/extensions/XPackExtensionCli.java @@ -9,25 +9,22 @@ import org.apache.log4j.BasicConfigurator; import org.apache.log4j.varia.NullAppender; import org.elasticsearch.cli.MultiCommand; import org.elasticsearch.cli.Terminal; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.node.internal.InternalSettingsPreparer; /** * A cli tool for adding, removing and listing extensions for x-pack. */ public class XPackExtensionCli extends MultiCommand { - public XPackExtensionCli(Environment env) { + public XPackExtensionCli() { super("A tool for managing installed x-pack extensions"); - subcommands.put("list", new ListXPackExtensionCommand(env)); - subcommands.put("install", new InstallXPackExtensionCommand(env)); - subcommands.put("remove", new RemoveXPackExtensionCommand(env)); + subcommands.put("list", new ListXPackExtensionCommand()); + subcommands.put("install", new InstallXPackExtensionCommand()); + subcommands.put("remove", new RemoveXPackExtensionCommand()); } public static void main(String[] args) throws Exception { BasicConfigurator.configure(new NullAppender()); - Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, Terminal.DEFAULT); - exit(new XPackExtensionCli(env).main(args, Terminal.DEFAULT)); + exit(new XPackExtensionCli().main(args, Terminal.DEFAULT)); } + } diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommandTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommandTests.java index 33d96ccbb03..fe04b60844f 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommandTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/InstallXPackExtensionCommandTests.java @@ -12,34 +12,37 @@ import org.elasticsearch.cli.UserError; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; +import org.junit.Before; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.DirectoryStream; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; -import java.nio.file.FileVisitResult; -import java.nio.file.NoSuchFileException; import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @LuceneTestCase.SuppressFileSystems("*") public class InstallXPackExtensionCommandTests extends ESTestCase { - /** - * Creates a test environment with plugins and xpack extensions directories. - */ - static Environment createEnv() throws IOException { - Path home = createTempDir(); + + Path home; + Environment env; + + @Before + public void setUp() throws Exception { + super.setUp(); + home = createTempDir(); Files.createDirectories(home.resolve("org/elasticsearch/xpack/extensions").resolve("xpack").resolve("extensions")); - Settings settings = Settings.builder() - .put("path.home", home) - .build(); - return new Environment(settings); + env = new Environment(Settings.builder().put("path.home", home.toString()).build()); } /** @@ -84,9 +87,11 @@ public class InstallXPackExtensionCommandTests extends ESTestCase { return writeZip(structure); } - static MockTerminal installExtension(String extensionUrl, Environment env) throws Exception { + static MockTerminal installExtension(String extensionUrl, Path home) throws Exception { + Map settings = new HashMap<>(); + settings.put("path.home", home.toString()); MockTerminal terminal = new MockTerminal(); - new InstallXPackExtensionCommand(env).execute(terminal, extensionUrl, true); + new InstallXPackExtensionCommand().execute(terminal, extensionUrl, true, settings); return terminal; } @@ -108,77 +113,65 @@ public class InstallXPackExtensionCommandTests extends ESTestCase { } public void testSomethingWorks() throws Exception { - Environment env = createEnv(); Path extDir = createTempDir(); String extZip = createExtension("fake", extDir); - installExtension(extZip, env); + installExtension(extZip, home); assertExtension("fake", extDir, env); } public void testSpaceInUrl() throws Exception { - Environment env = createEnv(); Path extDir = createTempDir(); String extZip = createExtension("fake", extDir); Path extZipWithSpaces = createTempFile("foo bar", ".zip"); try (InputStream in = new URL(extZip).openStream()) { Files.copy(in, extZipWithSpaces, StandardCopyOption.REPLACE_EXISTING); } - installExtension(extZipWithSpaces.toUri().toURL().toString(), env); + installExtension(extZipWithSpaces.toUri().toURL().toString(), home); assertExtension("fake", extDir, env); } public void testMalformedUrlNotMaven() throws Exception { // has two colons, so it appears similar to maven coordinates MalformedURLException e = expectThrows(MalformedURLException.class, () -> { - installExtension("://host:1234", createEnv()); + installExtension("://host:1234", home); }); assertTrue(e.getMessage(), e.getMessage().contains("no protocol")); } public void testJarHell() throws Exception { - Environment env = createEnv(); Path extDir = createTempDir(); writeJar(extDir.resolve("other.jar"), "FakeExtension"); String extZip = createExtension("fake", extDir); // adds extension.jar with FakeExtension - IllegalStateException e = expectThrows(IllegalStateException.class, () -> { - installExtension(extZip, env); - }); + IllegalStateException e = expectThrows(IllegalStateException.class, () -> installExtension(extZip, home)); assertTrue(e.getMessage(), e.getMessage().contains("jar hell")); assertInstallCleaned(env); } public void testIsolatedExtension() throws Exception { - Environment env = createEnv(); // these both share the same FakeExtension class Path extDir1 = createTempDir(); String extZip1 = createExtension("fake1", extDir1); - installExtension(extZip1, env); + installExtension(extZip1, home); Path extDir2 = createTempDir(); String extZip2 = createExtension("fake2", extDir2); - installExtension(extZip2, env); + installExtension(extZip2, home); assertExtension("fake1", extDir1, env); assertExtension("fake2", extDir2, env); } public void testExistingExtension() throws Exception { - Environment env = createEnv(); String extZip = createExtension("fake", createTempDir()); - installExtension(extZip, env); - UserError e = expectThrows(UserError.class, () -> { - installExtension(extZip, env); - }); + installExtension(extZip, home); + UserError e = expectThrows(UserError.class, () -> installExtension(extZip, home)); assertTrue(e.getMessage(), e.getMessage().contains("already exists")); assertInstallCleaned(env); } public void testMissingDescriptor() throws Exception { - Environment env = createEnv(); Path extDir = createTempDir(); Files.createFile(extDir.resolve("fake.yml")); String extZip = writeZip(extDir); - NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> { - installExtension(extZip, env); - }); + NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> installExtension(extZip, home)); assertTrue(e.getMessage(), e.getMessage().contains("x-pack-extension-descriptor.properties")); assertInstallCleaned(env); } diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommandTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommandTests.java index c4f484daa9e..87ef2d85536 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommandTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/ListXPackExtensionCommandTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.cli.MockTerminal; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; +import org.junit.Before; import java.io.IOException; import java.nio.file.Files; @@ -19,60 +20,55 @@ import java.nio.file.Path; @LuceneTestCase.SuppressFileSystems("*") public class ListXPackExtensionCommandTests extends ESTestCase { - Environment createEnv() throws IOException { - Path home = createTempDir(); - Settings settings = Settings.builder() - .put("path.home", home) - .build(); - return new Environment(settings); + private Path home; + + @Before + public void setUp() throws Exception { + super.setUp(); + home = createTempDir(); } - Path createExtensionDir(Environment env) throws IOException { - Path path = env.pluginsFile().resolve("x-pack").resolve("extensions"); + private static Path createExtensionDir(final Path home) throws IOException { + final Environment env = new Environment(Settings.builder().put("path.home", home.toString()).build()); + final Path path = env.pluginsFile().resolve("x-pack").resolve("extensions"); return Files.createDirectories(path); } - static MockTerminal listExtensions(Environment env) throws Exception { + static MockTerminal listExtensions(Path home) throws Exception { MockTerminal terminal = new MockTerminal(); - String[] args = {}; - int status = new ListXPackExtensionCommand(env).main(args, terminal); + int status = new ListXPackExtensionCommand().main(new String[] { "-Epath.home=" + home }, terminal); assertEquals(ExitCodes.OK, status); return terminal; } public void testExtensionsDirMissing() throws Exception { - Environment env = createEnv(); - Path extDir = createExtensionDir(env); + Path extDir = createExtensionDir(home); Files.delete(extDir); - IOException e = expectThrows(IOException.class, () -> { - listExtensions(env); - }); + IOException e = expectThrows(IOException.class, () -> listExtensions(home)); assertTrue(e.getMessage(), e.getMessage().contains("Extensions directory missing")); } public void testNoExtensions() throws Exception { - Environment env = createEnv(); - createExtensionDir(env); - MockTerminal terminal = listExtensions(env); + createExtensionDir(home); + MockTerminal terminal = listExtensions(home); assertTrue(terminal.getOutput(), terminal.getOutput().isEmpty()); } public void testOneExtension() throws Exception { - Environment env = createEnv(); - Path extDir = createExtensionDir(env); + Path extDir = createExtensionDir(home); Files.createDirectory(extDir.resolve("fake")); - MockTerminal terminal = listExtensions(env); + MockTerminal terminal = listExtensions(home); assertTrue(terminal.getOutput(), terminal.getOutput().contains("fake")); } public void testTwoExtensions() throws Exception { - Environment env = createEnv(); - Path extDir = createExtensionDir(env); + Path extDir = createExtensionDir(home); Files.createDirectory(extDir.resolve("fake1")); Files.createDirectory(extDir.resolve("fake2")); - MockTerminal terminal = listExtensions(env); + MockTerminal terminal = listExtensions(home); String output = terminal.getOutput(); assertTrue(output, output.contains("fake1")); assertTrue(output, output.contains("fake2")); } + } diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommandTests.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommandTests.java index fec7b42e86f..fda0b00f3e3 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommandTests.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/extensions/RemoveXPackExtensionCommandTests.java @@ -11,22 +11,26 @@ import org.elasticsearch.cli.UserError; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; +import org.junit.Before; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; @LuceneTestCase.SuppressFileSystems("*") public class RemoveXPackExtensionCommandTests extends ESTestCase { - /** Creates a test environment with bin, config and plugins directories. */ - static Environment createEnv() throws IOException { - Path home = createTempDir(); - Settings settings = Settings.builder() - .put("path.home", home) - .build(); - return new Environment(settings); + private Path home; + private Environment env; + + @Before + public void setUp() throws Exception { + super.setUp(); + home = createTempDir(); + env = new Environment(Settings.builder().put("path.home", home.toString()).build()); } Path createExtensionDir(Environment env) throws IOException { @@ -34,9 +38,11 @@ public class RemoveXPackExtensionCommandTests extends ESTestCase { return Files.createDirectories(path); } - static MockTerminal removeExtension(String name, Environment env) throws Exception { + static MockTerminal removeExtension(String name, Path home) throws Exception { + Map settings = new HashMap<>(); + settings.put("path.home", home.toString()); MockTerminal terminal = new MockTerminal(); - new RemoveXPackExtensionCommand(env).execute(terminal, name); + new RemoveXPackExtensionCommand().execute(terminal, name, settings); return terminal; } @@ -51,25 +57,22 @@ public class RemoveXPackExtensionCommandTests extends ESTestCase { } public void testMissing() throws Exception { - Environment env = createEnv(); Path extDir = createExtensionDir(env); - UserError e = expectThrows(UserError.class, () -> { - removeExtension("dne", env); - }); + UserError e = expectThrows(UserError.class, () -> removeExtension("dne", home)); assertTrue(e.getMessage(), e.getMessage().contains("Extension dne not found")); assertRemoveCleaned(extDir); } public void testBasic() throws Exception { - Environment env = createEnv(); Path extDir = createExtensionDir(env); Files.createDirectory(extDir.resolve("fake")); Files.createFile(extDir.resolve("fake").resolve("extension.jar")); Files.createDirectory(extDir.resolve("fake").resolve("subdir")); Files.createDirectory(extDir.resolve("other")); - removeExtension("fake", env); + removeExtension("fake", home); assertFalse(Files.exists(extDir.resolve("fake"))); assertTrue(Files.exists(extDir.resolve("other"))); assertRemoveCleaned(extDir); } + } diff --git a/elasticsearch/x-pack/watcher/bin/x-pack/croneval b/elasticsearch/x-pack/watcher/bin/x-pack/croneval index edfe1041755..4194b2d0dc6 100755 --- a/elasticsearch/x-pack/watcher/bin/x-pack/croneval +++ b/elasticsearch/x-pack/watcher/bin/x-pack/croneval @@ -70,29 +70,6 @@ elif [ -f "/etc/default/elasticsearch" ]; then . "/etc/default/elasticsearch" fi -# Parse any long getopt options and put them into properties -ARGCOUNT=$# -COUNT=0 -while [ $COUNT -lt $ARGCOUNT ] -do - case $1 in - --*) properties="$properties $1 $2" - shift ; shift; COUNT=$(($COUNT+2)) - ;; - *) set -- "$@" "$1"; shift; COUNT=$(($COUNT+1)) - esac -done - -# check if properties already has a config file or config dir -if [ -e "$CONF_DIR" ]; then - case "$properties" in - *-Des.default.path.conf=*) ;; - *) - properties="$properties -Des.default.path.conf=$CONF_DIR" - ;; - esac -fi - export HOSTNAME=`hostname -s` # include watcher jars in classpath @@ -112,8 +89,14 @@ if [ ! -z "$CONF_FILE" ]; then exit 1 fi +declare -a args=("$@") + +if [ -e "$CONF_DIR" ]; then + args=("${args[@]}" -Edefault.path.conf="$CONF_DIR") +fi + cd "$ES_HOME" > /dev/null -"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.watcher.trigger.schedule.tool.CronEvalTool "$@" $properties +"$JAVA" $ES_JAVA_OPTS -cp "$ES_CLASSPATH" -Des.path.home="$ES_HOME" org.elasticsearch.xpack.watcher.trigger.schedule.tool.CronEvalTool "${args[@]}" status=$? cd - > /dev/null exit $status From a2993810f9a06812b7694def0c2d1a37d56c4d67 Mon Sep 17 00:00:00 2001 From: Areek Zillur Date: Thu, 19 May 2016 17:15:04 -0400 Subject: [PATCH 09/16] Fix rest test to adapt to license removal behaviour Now we explicitly install a license in rest test cluster Original commit: elastic/x-pack-elasticsearch@59cc837d0f121db69977c5975233681798fdfdde --- .../test/license/20_put_license.yaml | 4 ++++ .../xpack/test/rest/XPackRestTestCase.java | 23 ++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/elasticsearch/x-pack/license-plugin/src/test/resources/rest-api-spec/test/license/20_put_license.yaml b/elasticsearch/x-pack/license-plugin/src/test/resources/rest-api-spec/test/license/20_put_license.yaml index be2592d265a..21af326eeeb 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/resources/rest-api-spec/test/license/20_put_license.yaml +++ b/elasticsearch/x-pack/license-plugin/src/test/resources/rest-api-spec/test/license/20_put_license.yaml @@ -4,6 +4,7 @@ ## current license version - do: license.post: + acknowledge: true body: | {"license":{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA0lKPZ0a7aZquUltho/AAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}} @@ -18,6 +19,7 @@ ## bwc for licenses format - do: license.post: + acknowledge: true body: | {"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"basic","issue_date_in_millis":1411948800000,"expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAgAAAA0lKPZ0a7aZquUltho/AAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQAALuQ44S3IG6SzolcXVJ6Z4CIXORDrYQ+wdLCeey0XdujTslAOj+k+vNgo6wauc7Uswi01esHu4lb5IgpvKy7RRCbh5bj/z2ubu2qMJqopp9BQyD7VQjVfqmG6seUMJwJ1a5Avvm9r41YPSPcrii3bKK2e1l6jK6N8ibCvnTyY/XkYGCJrBWTSJePDbg6ErbyodrZ37x1StLbPWcNAkmweyHjDJnvYnbeZZO7A3NmubXZjW7Ttf8/YwQyE00PqMcl7fVPY3hkKpAeHf8aaJbqkKYbqZuER3EWJX7ZvLVb1dNdNg8aXRn7YrkQcYwWgptYQpfV+D7yEJ4j5muAEoler"}]} @@ -31,6 +33,7 @@ ## license version: 1.x - do: license.post: + acknowledge: true body: | {"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"subscription","subscription_type":"gold","issue_date_in_millis":1411948800000,"feature":"shield","expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA0LVAywwpSH94cyXr4zAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQA4qscc/URRZVdFoLwgy9dqybYEQLW8YLkiAyPV5XHHHdtk+dtZIepiNEDkUXhSX2waVJlsNRF8/4kqplDfwNoD2TUM8fTgiIfiSiZYGDTGST+yW/5eAveEU5J5v1liBN27bwkqL+V4YAa0Tcm7NKKwjScWKAHiTU3vF8chPkGfCHE0kQgVwPC9RE82pTw0s6/uR4PfLGNFfqPM0uiE5nucfVrtj89JQiO/KA/7ZyFbo7VTNXxZQt7T7rZWBCP9KIjptXzcWuk08Q5S+rSoJNYbFo3HGKtrCVsRz/55rceNtdwKKXu1IwnSeir4I1/KLduQTtFLy0+1th87VS8T88UT"}]} @@ -44,6 +47,7 @@ ## multiple licenses version: 1.x - do: license.post: + acknowledge: true body: | {"licenses":[{"uid":"893361dc-9749-4997-93cb-802e3d7fa4a8","type":"internal","subscription_type":"none","issue_date_in_millis":1411948800000,"feature":"shield","expiry_date_in_millis":1440892799999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA04Q4ky3rFyyWLFkytEAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQBxMvUMn4h2E4R4TQMijahTxQj4LPQO4f1M79UxX/XkDlGcH+J5pRHx08OtTRPsFL1lED+h+PIXx307Vo+PNDsOxrWvoYZeYBkOLAO3ny9vhQga+52jYhMxIuFrT9xbcSCSNpMhGojgOIPU2WgiopVdVcimo1+Gk8VtklPB1wPwFzfOjOnPgp/Icx3WYpfkeAUUOyWUYiFIBAe4bnz84iF+xwLKbgYk6aHF25ECBtdb/Uruhcm9+jEFpoIEUtCouvvk9C+NJZ4OickV4xpRgaRG2x9PONH8ZN0QGhGYhJGbisoCxuDmlLsyVxqxfMu3n/r7/jdsEJScjAlSrsLDOu6H"},{"uid":"893361dc-9749-4997-93cb-802e3dofh7aa","type":"internal","subscription_type":"none","issue_date_in_millis":1443484800000,"feature":"watcher","expiry_date_in_millis":1914278399999,"max_nodes":1,"issued_to":"issuedTo","issuer":"issuer","signature":"AAAAAQAAAA0Sc90guRIaQEmgLvMnAAABmC9ZN0hjZDBGYnVyRXpCOW5Bb3FjZDAxOWpSbTVoMVZwUzRxVk1PSmkxakxZdW5IMlhlTHNoN1N2MXMvRFk4d3JTZEx3R3RRZ0pzU3lobWJKZnQvSEFva0ppTHBkWkprZWZSQi9iNmRQNkw1SlpLN0lDalZCS095MXRGN1lIZlpYcVVTTnFrcTE2dzhJZmZrdFQrN3JQeGwxb0U0MXZ0dDJHSERiZTVLOHNzSDByWnpoZEphZHBEZjUrTVBxRENNSXNsWWJjZllaODdzVmEzUjNiWktNWGM5TUhQV2plaUo4Q1JOUml4MXNuL0pSOEhQaVB2azhmUk9QVzhFeTFoM1Q0RnJXSG53MWk2K055c28zSmRnVkF1b2JSQkFLV2VXUmVHNDZ2R3o2VE1qbVNQS2lxOHN5bUErZlNIWkZSVmZIWEtaSU9wTTJENDVvT1NCYklacUYyK2FwRW9xa0t6dldMbmMzSGtQc3FWOTgzZ3ZUcXMvQkt2RUZwMFJnZzlvL2d2bDRWUzh6UG5pdENGWFRreXNKNkE9PQAAAQCQ94dju0pnDZR3Uuypi0ic3aQJ+nvVqe+U8u79Dga5n1qIjcHDh7HvIBJEkF+tnVPlo/PXV/x7BZSwVY1PVErit+6rYix1yuHEgqwxmx/VdRICjCaZM6tk0Ob4dZCPv6Ebn2Mmk89KHC/PwiLPqF6QfwV/Pkpa8k2A3ORJmvYSDvXhe6tCs8dqc4ebrsFxqrZjwWh5CZSpzqqZBFXlngDv2N0hHhpGlueRszD0JJ5dfEL5ZA1DDOrgO9OJVejSHyRqe1L5QRUNdXPVfS+EAG0Dd1cNdJ/sMpYCPnVjbw6iq2/YgM3cuztsXVBY7ij4WnoP3ce7Zjs9TwHn+IqzftC6"}]} diff --git a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java index 9cf0da510e6..675834e9245 100644 --- a/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java +++ b/elasticsearch/x-pack/src/test/java/org/elasticsearch/xpack/test/rest/XPackRestTestCase.java @@ -10,6 +10,8 @@ import java.io.InputStreamReader; import java.net.URI; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; import java.util.Map; import com.carrotsearch.randomizedtesting.annotations.Name; @@ -21,18 +23,20 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.lucene.util.IOUtils; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; -import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.license.plugin.TestUtils; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.parser.RestTestParseException; -import org.elasticsearch.xpack.common.xcontent.XContentUtils; import org.junit.After; import org.junit.Before; @@ -82,6 +86,19 @@ public abstract class XPackRestTestCase extends ESRestTestCase { } } + @Before + public void installLicense() throws Exception { + final XContentBuilder builder = XContentFactory.jsonBuilder(); + TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)).toXContent(builder, ToXContent.EMPTY_PARAMS); + final BytesReference bytes = builder.bytes(); + try (XContentParser parser = XContentFactory.xContent(bytes).createParser(bytes)) { + final List> bodies = Collections.singletonList(Collections.singletonMap("license", + parser.map())); + getAdminExecutionContext().callApi("license.post", Collections.singletonMap("acknowledge", "true"), + bodies, Collections.singletonMap("Authorization", BASIC_AUTH_VALUE)); + } + } + @After public void clearShieldUsersAndRoles() throws Exception { // we cannot delete the .security index from a rest test since we aren't the internal user, lets wipe the data From 26a07766f0a49c13aecfb3399bca2ee5a581a0d7 Mon Sep 17 00:00:00 2001 From: Areek Zillur Date: Thu, 19 May 2016 18:20:01 -0400 Subject: [PATCH 10/16] fix license notification test bug Original commit: elastic/x-pack-elasticsearch@ec1257d3e14d64c71c74ed0d8f3ae88c03b049e9 --- .../plugin/core/LicensesExpiryNotificationTests.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java index 9e019976129..dceab4627aa 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/LicensesExpiryNotificationTests.java @@ -11,9 +11,7 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.license.plugin.TestUtils.AssertingLicensee; import org.elasticsearch.test.ESSingleNodeTestCase; -import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import static org.elasticsearch.license.plugin.TestUtils.awaitNoBlock; import static org.elasticsearch.license.plugin.TestUtils.awaitNoPendingTasks; @@ -194,7 +192,7 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { msg.append(dumpLicensingStates(states)); assertThat(msg.toString(), licensee.statuses.size(), equalTo(states.length)); for (int i = 0; i < states.length; i++) { - assertThat(msg.toString(), licensee.statuses.get(i), equalTo(states[i])); + assertThat(msg.toString(), licensee.statuses.get(i).getLicenseState(), equalTo(states[i])); } } @@ -202,10 +200,12 @@ public class LicensesExpiryNotificationTests extends ESSingleNodeTestCase { return dumpLicensingStates(statuses.toArray(new Licensee.Status[statuses.size()])); } - private String dumpLicensingStates(Licensee.Status... statuses) { - return dumpLicensingStates((LicenseState[]) Arrays.asList(statuses).stream() - .map(Licensee.Status::getLicenseState).collect(Collectors.toList()).toArray()); + LicenseState[] states = new LicenseState[statuses.length]; + for (int i = 0; i < statuses.length; i++) { + states[i] = statuses[i].getLicenseState(); + } + return dumpLicensingStates(states); } private String dumpLicensingStates(LicenseState... states) { From 71b78579a10e7613b738ec94e9d0ab0518b07c95 Mon Sep 17 00:00:00 2001 From: jaymode Date: Fri, 20 May 2016 08:10:55 -0400 Subject: [PATCH 11/16] test: ensure address is resolvable in CertUtilsTests#testSubjectAlternativeNames We check for an expected length but this is only valid if the address can be resolved and on some systems 127.0.0.1 may not map to a name. Original commit: elastic/x-pack-elasticsearch@2f7c8da242151dd57caa2f38cf81bf78bb3d8de0 --- .../org/elasticsearch/shield/ssl/CertUtilsTests.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/ssl/CertUtilsTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/ssl/CertUtilsTests.java index 39daec1df5a..ca6d3e09ae5 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/ssl/CertUtilsTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/ssl/CertUtilsTests.java @@ -7,7 +7,9 @@ package org.elasticsearch.shield.ssl; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; +import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.network.InetAddresses; +import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.test.ESTestCase; import java.io.InputStream; @@ -113,7 +115,8 @@ public class CertUtilsTests extends ESTestCase { GeneralName[] generalNameArray = generalNames.getNames(); assertThat(generalNameArray, notNullValue()); - if (resolveName) { + logger.info("resolve name [{}], address [{}], subject alt names [{}]", resolveName, NetworkAddress.format(address), generalNames); + if (resolveName && isResolvable(address)) { assertThat(generalNameArray.length, is(2)); int firstType = generalNameArray[0].getTagNo(); if (firstType == GeneralName.iPAddress) { @@ -129,6 +132,12 @@ public class CertUtilsTests extends ESTestCase { } } + @SuppressForbidden(reason = "need to use getHostName to resolve DNS name and getHostAddress to ensure we resolved the name") + private boolean isResolvable(InetAddress inetAddress) { + String hostname = inetAddress.getHostName(); + return hostname.equals(inetAddress.getHostAddress()) == false; + } + public void testIsAnyLocalAddress() throws Exception { InetAddress address = mock(InetAddress.class); when(address.isAnyLocalAddress()).thenReturn(true); From d55257401610b5eb58a07df12e79ffb4cceb72ae Mon Sep 17 00:00:00 2001 From: jaymode Date: Fri, 20 May 2016 08:11:26 -0400 Subject: [PATCH 12/16] test: set logger level differently after removal of support for es.* system properties Original commit: elastic/x-pack-elasticsearch@fcaa9bbcff4b67a61ccf0218bf7be75bb2b51049 --- elasticsearch/qa/smoke-test-plugins-ssl/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle b/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle index 8581f51a63c..05fc100d3f9 100644 --- a/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle +++ b/elasticsearch/qa/smoke-test-plugins-ssl/build.gradle @@ -178,7 +178,7 @@ integTest { 'bin/x-pack/users', 'useradd', 'monitoring_agent', '-p', 'changeme', '-r', 'remote_monitoring_agent' // Required to detect that the monitoring agent service has started - systemProperty 'es.logger.level', 'DEBUG' + setting 'logger.level', 'DEBUG' waitCondition = { node, ant -> // HTTPS check is tricky to do, so we wait for the log file to indicate that the node is started From 9dbbfd09f804a86bcd6f451a5d2eba7ef1fb45fa Mon Sep 17 00:00:00 2001 From: uboness Date: Wed, 11 May 2016 12:40:40 +0200 Subject: [PATCH 13/16] Introducing infrastructure for feature usage API - Each `XPackFeatureSet` can now return a `Usage` object that encapsulates the feature usage stats of the set - A new `/_xpack/usage` REST API is introduced to access the usage stats of all features - Intentionally not explicitly exposing the API in the `XPackClient` as this API is primarily meant for use by Kibana X-Pack (that said, it is still possible to call this API from the transport client using the `XPathUsageRequestBuilder`) - For now the usage stats that are returned are minimal, once this infrastructure is in, we'll start adding more stats Relates to elastic/elasticsearch#2210 Original commit: elastic/x-pack-elasticsearch@d651fe4b016a656d0468f142a20529a280573eed --- .../elasticsearch/graph/GraphFeatureSet.java | 40 ++++++- .../marvel/MonitoringFeatureSet.java | 110 +++++++++++++++++- .../marvel/agent/exporter/Exporter.java | 4 + .../shield/SecurityFeatureSet.java | 42 ++++++- .../elasticsearch/xpack/XPackFeatureSet.java | 53 +++++++++ .../org/elasticsearch/xpack/XPackPlugin.java | 5 + .../action/TransportXPackUsageAction.java | 42 +++++++ .../xpack/action/XPackInfoResponse.java | 7 +- .../xpack/action/XPackUsageAction.java | 32 +++++ .../xpack/action/XPackUsageRequest.java | 21 ++++ .../action/XPackUsageRequestBuilder.java | 22 ++++ .../xpack/action/XPackUsageResponse.java | 63 ++++++++++ .../rest/action/RestXPackUsageAction.java | 49 ++++++++ .../xpack/watcher/WatcherFeatureSet.java | 40 ++++++- 14 files changed, 520 insertions(+), 10 deletions(-) create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/TransportXPackUsageAction.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageAction.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequest.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequestBuilder.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageResponse.java create mode 100644 elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/rest/action/RestXPackUsageAction.java diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java index ea0fdf18e7c..b83db912369 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java @@ -7,9 +7,14 @@ package org.elasticsearch.graph; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.XPackFeatureSet; +import java.io.IOException; + /** * */ @@ -19,9 +24,10 @@ public class GraphFeatureSet implements XPackFeatureSet { private final GraphLicensee licensee; @Inject - public GraphFeatureSet(Settings settings, @Nullable GraphLicensee licensee) { + public GraphFeatureSet(Settings settings, @Nullable GraphLicensee licensee, NamedWriteableRegistry namedWriteableRegistry) { this.enabled = Graph.enabled(settings); this.licensee = licensee; + namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); } @Override @@ -43,4 +49,36 @@ public class GraphFeatureSet implements XPackFeatureSet { public boolean enabled() { return enabled; } + + @Override + public Usage usage() { + return new Usage(available(), enabled()); + } + + static class Usage extends XPackFeatureSet.Usage { + + static final String WRITEABLE_NAME = writeableName(Graph.NAME); + + public Usage(StreamInput input) throws IOException { + super(input); + } + + public Usage(boolean available, boolean enabled) { + super(Graph.NAME, available, enabled); + } + + @Override + public String getWriteableName() { + return WRITEABLE_NAME; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject() + .field(Field.AVAILABLE, available) + .field(Field.ENABLED, enabled) + .endObject(); + + } + } } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java index 03a4b61b7b8..9ba1777b806 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java @@ -7,9 +7,19 @@ package org.elasticsearch.marvel; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.marvel.agent.exporter.Exporter; +import org.elasticsearch.marvel.agent.exporter.Exporters; +import org.elasticsearch.marvel.agent.exporter.http.HttpExporter; +import org.elasticsearch.marvel.agent.exporter.local.LocalExporter; import org.elasticsearch.xpack.XPackFeatureSet; +import java.io.IOException; + /** * */ @@ -17,11 +27,15 @@ public class MonitoringFeatureSet implements XPackFeatureSet { private final boolean enabled; private final MonitoringLicensee licensee; + private final Exporters exporters; @Inject - public MonitoringFeatureSet(Settings settings, @Nullable MonitoringLicensee licensee) { + public MonitoringFeatureSet(Settings settings, @Nullable MonitoringLicensee licensee, Exporters exporters, + NamedWriteableRegistry namedWriteableRegistry) { this.enabled = MonitoringSettings.ENABLED.get(settings); this.licensee = licensee; + this.exporters = exporters; + namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); } @Override @@ -43,4 +57,98 @@ public class MonitoringFeatureSet implements XPackFeatureSet { public boolean enabled() { return enabled; } + + @Override + public Usage usage() { + + int enabledLocalExporters = 0; + int enabledHttpExporters = 0; + int enabledUnknownExporters = 0; + for (Exporter exporter : exporters) { + if (exporter.config().enabled()) { + switch (exporter.type()) { + case LocalExporter.TYPE: + enabledLocalExporters++; + break; + case HttpExporter.TYPE: + enabledHttpExporters++; + break; + default: + enabledUnknownExporters++; + } + } + } + + return new Usage(available(), enabled(), enabledLocalExporters, enabledHttpExporters, enabledUnknownExporters); + } + + static class Usage extends XPackFeatureSet.Usage { + + private static String WRITEABLE_NAME = writeableName(Monitoring.NAME); + + private final int enabledLocalExporters; + private final int enabledHttpExporters; + private final int enabledUnknownExporters; + + public Usage(StreamInput in) throws IOException { + super(in); + this.enabledLocalExporters = in.readVInt(); + this.enabledHttpExporters = in.readVInt(); + this.enabledUnknownExporters = in.readVInt(); + } + + public Usage(boolean available, boolean enabled, int enabledLocalExporters, int enabledHttpExporters, int enabledUnknownExporters) { + super(Monitoring.NAME, available, enabled); + this.enabledLocalExporters = enabledLocalExporters; + this.enabledHttpExporters = enabledHttpExporters; + this.enabledUnknownExporters = enabledUnknownExporters; + } + + @Override + public boolean available() { + return available; + } + + @Override + public boolean enabled() { + return enabled; + } + + @Override + public String getWriteableName() { + return WRITEABLE_NAME; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeVInt(enabledLocalExporters); + out.writeVInt(enabledHttpExporters); + out.writeVInt(enabledUnknownExporters); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(Field.AVAILABLE, available); + builder.field(Field.ENABLED, enabled); + + builder.startObject(Field.ENABLED_EXPORTERS); + builder.field(Field.LOCAL, enabledLocalExporters); + builder.field(Field.HTTP, enabledHttpExporters); + if (enabledUnknownExporters > 0) { + builder.field(Field.UNKNOWN, enabledUnknownExporters); + } + builder.endObject(); + + return builder.endObject(); + } + + interface Field extends XPackFeatureSet.Usage.Field { + String ENABLED_EXPORTERS = "enabled_exporters"; + String LOCAL = "_local"; + String HTTP = "http"; + String UNKNOWN = "_unknown"; + } + } } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/Exporter.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/Exporter.java index 6bf3b09564f..bf91863cfc0 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/Exporter.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/Exporter.java @@ -41,6 +41,10 @@ public abstract class Exporter implements AutoCloseable { return config.name; } + public Config config() { + return config; + } + public boolean masterOnly() { return false; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java index e36c17ddec6..6a53e72eb52 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java @@ -7,9 +7,15 @@ package org.elasticsearch.shield; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.marvel.Monitoring; import org.elasticsearch.xpack.XPackFeatureSet; +import java.io.IOException; + /** * */ @@ -19,9 +25,11 @@ public class SecurityFeatureSet implements XPackFeatureSet { private final SecurityLicenseState licenseState; @Inject - public SecurityFeatureSet(Settings settings, @Nullable SecurityLicenseState licenseState) { + public SecurityFeatureSet(Settings settings, @Nullable SecurityLicenseState licenseState, + NamedWriteableRegistry namedWriteableRegistry) { this.enabled = Security.enabled(settings); this.licenseState = licenseState; + namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); } @Override @@ -43,4 +51,36 @@ public class SecurityFeatureSet implements XPackFeatureSet { public boolean enabled() { return enabled; } + + @Override + public XPackFeatureSet.Usage usage() { + return new Usage(available(), enabled()); + } + + static class Usage extends XPackFeatureSet.Usage { + + private static final String WRITEABLE_NAME = writeableName(Security.NAME); + + public Usage(StreamInput input) throws IOException { + super(input); + } + + public Usage(boolean available, boolean enabled) { + super(Security.NAME, available, enabled); + } + + @Override + public String getWriteableName() { + return WRITEABLE_NAME; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject() + .field(Field.AVAILABLE, available) + .field(Field.ENABLED, enabled) + .endObject(); + + } + } } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java index af26f5ef8d2..ef0717c985d 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java @@ -5,6 +5,13 @@ */ package org.elasticsearch.xpack; +import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContent; + +import java.io.IOException; + /** * */ @@ -18,4 +25,50 @@ public interface XPackFeatureSet { boolean enabled(); + Usage usage(); + + abstract class Usage implements ToXContent, NamedWriteable { + + protected final String name; + protected final boolean available; + protected final boolean enabled; + + public Usage(StreamInput input) throws IOException { + this(input.readString(), input.readBoolean(), input.readBoolean()); + } + + public Usage(String name, boolean available, boolean enabled) { + this.name = name; + this.available = available; + this.enabled = enabled; + } + + public String name() { + return name; + } + + public boolean available() { + return available; + } + + public boolean enabled() { + return enabled; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeBoolean(available); + out.writeBoolean(enabled); + } + + protected interface Field { + String AVAILABLE = "available"; + String ENABLED = "enabled"; + } + + protected static String writeableName(String featureName) { + return "xpack.usage." + featureName; + } + } + } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index 81ad4fc069b..19b705fa770 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -27,7 +27,9 @@ import org.elasticsearch.script.ScriptModule; import org.elasticsearch.shield.Security; import org.elasticsearch.shield.authc.AuthenticationModule; import org.elasticsearch.xpack.action.TransportXPackInfoAction; +import org.elasticsearch.xpack.action.TransportXPackUsageAction; import org.elasticsearch.xpack.action.XPackInfoAction; +import org.elasticsearch.xpack.action.XPackUsageAction; import org.elasticsearch.xpack.common.http.HttpClientModule; import org.elasticsearch.xpack.common.init.LazyInitializationModule; import org.elasticsearch.xpack.common.init.LazyInitializationService; @@ -37,6 +39,7 @@ import org.elasticsearch.xpack.extensions.XPackExtensionsService; import org.elasticsearch.xpack.notification.Notification; import org.elasticsearch.xpack.rest.action.RestXPackInfoAction; import org.elasticsearch.xpack.common.text.TextTemplateModule; +import org.elasticsearch.xpack.rest.action.RestXPackUsageAction; import org.elasticsearch.xpack.watcher.Watcher; import java.nio.file.Path; @@ -194,6 +197,7 @@ public class XPackPlugin extends Plugin { public void onModule(NetworkModule module) { if (!transportClientMode) { module.registerRestHandler(RestXPackInfoAction.class); + module.registerRestHandler(RestXPackUsageAction.class); } licensing.onModule(module); monitoring.onModule(module); @@ -205,6 +209,7 @@ public class XPackPlugin extends Plugin { public void onModule(ActionModule module) { if (!transportClientMode) { module.registerAction(XPackInfoAction.INSTANCE, TransportXPackInfoAction.class); + module.registerAction(XPackUsageAction.INSTANCE, TransportXPackUsageAction.class); } licensing.onModule(module); monitoring.onModule(module); diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/TransportXPackUsageAction.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/TransportXPackUsageAction.java new file mode 100644 index 00000000000..0aab9211c00 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/TransportXPackUsageAction.java @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.action; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.XPackFeatureSet; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + */ +public class TransportXPackUsageAction extends HandledTransportAction { + + private final Set featureSets; + + @Inject + public TransportXPackUsageAction(Settings settings, ThreadPool threadPool, TransportService transportService, + ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, + Set featureSets) { + super(settings, XPackInfoAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, + XPackUsageRequest::new); + this.featureSets = featureSets; + } + + @Override + protected void doExecute(XPackUsageRequest request, ActionListener listener) { + List usages = featureSets.stream().map(XPackFeatureSet::usage).collect(Collectors.toList()); + listener.onResponse(new XPackUsageResponse(usages)); + } +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackInfoResponse.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackInfoResponse.java index b5bcf9d0228..c7f08ae09c1 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackInfoResponse.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackInfoResponse.java @@ -14,7 +14,6 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.license.core.License; import org.elasticsearch.xpack.XPackBuild; -import org.elasticsearch.xpack.XPackFeatureSet; import java.io.IOException; import java.util.ArrayList; @@ -219,7 +218,7 @@ public class XPackInfoResponse extends ActionResponse { } } - public static class FeatureSet implements XPackFeatureSet, ToXContent, Writeable { + public static class FeatureSet implements ToXContent, Writeable { private final String name; private final @Nullable String description; @@ -237,23 +236,19 @@ public class XPackInfoResponse extends ActionResponse { this.enabled = enabled; } - @Override public String name() { return name; } - @Override @Nullable public String description() { return description; } - @Override public boolean available() { return available; } - @Override public boolean enabled() { return enabled; } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageAction.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageAction.java new file mode 100644 index 00000000000..6d148f4d5a8 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageAction.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.action; + +import org.elasticsearch.action.Action; +import org.elasticsearch.client.ElasticsearchClient; + +/** + * + */ +public class XPackUsageAction extends Action { + + public static final String NAME = "cluster:monitor/xpack/usage"; + public static final XPackUsageAction INSTANCE = new XPackUsageAction(); + + public XPackUsageAction() { + super(NAME); + } + + @Override + public XPackUsageRequestBuilder newRequestBuilder(ElasticsearchClient client) { + return new XPackUsageRequestBuilder(client); + } + + @Override + public XPackUsageResponse newResponse() { + return new XPackUsageResponse(); + } +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequest.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequest.java new file mode 100644 index 00000000000..5b91a7565d1 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequest.java @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.action; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; + +/** + * + */ +public class XPackUsageRequest extends ActionRequest { + + @Override + public ActionRequestValidationException validate() { + return null; + } + +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequestBuilder.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequestBuilder.java new file mode 100644 index 00000000000..fe1986445ce --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageRequestBuilder.java @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.action; + +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.client.ElasticsearchClient; + +/** + */ +public class XPackUsageRequestBuilder extends ActionRequestBuilder { + + public XPackUsageRequestBuilder(ElasticsearchClient client) { + this(client, XPackUsageAction.INSTANCE); + } + + public XPackUsageRequestBuilder(ElasticsearchClient client, XPackUsageAction action) { + super(client, action, new XPackUsageRequest()); + } +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageResponse.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageResponse.java new file mode 100644 index 00000000000..9906acaa181 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/action/XPackUsageResponse.java @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.action; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.license.core.License; +import org.elasticsearch.xpack.XPackBuild; +import org.elasticsearch.xpack.XPackFeatureSet; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + */ +public class XPackUsageResponse extends ActionResponse { + + private List usages; + + public XPackUsageResponse() {} + + public XPackUsageResponse(List usages) { + this.usages = usages; + } + + public List getUsages() { + return usages; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeVInt(usages.size()); + for (XPackFeatureSet.Usage usage : usages) { + out.writeNamedWriteable(usage); + } + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + int size = in.readVInt(); + usages = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + usages.add(in.readNamedWriteable(XPackFeatureSet.Usage.class)); + } + } +} diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/rest/action/RestXPackUsageAction.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/rest/action/RestXPackUsageAction.java new file mode 100644 index 00000000000..1a552fc4a01 --- /dev/null +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/rest/action/RestXPackUsageAction.java @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.rest.action; + +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.rest.BytesRestResponse; +import org.elasticsearch.rest.RestChannel; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.rest.RestResponse; +import org.elasticsearch.rest.action.support.RestBuilderListener; +import org.elasticsearch.xpack.XPackClient; +import org.elasticsearch.xpack.XPackFeatureSet; +import org.elasticsearch.xpack.action.XPackUsageRequestBuilder; +import org.elasticsearch.xpack.action.XPackUsageResponse; +import org.elasticsearch.xpack.rest.XPackRestHandler; + +import static org.elasticsearch.rest.RestRequest.Method.GET; +import static org.elasticsearch.rest.RestStatus.OK; + +public class RestXPackUsageAction extends XPackRestHandler { + + @Inject + public RestXPackUsageAction(Settings settings, RestController controller, Client client) { + super(settings, client); + controller.registerHandler(GET, URI_BASE + "/usage", this); + } + + @Override + protected void handleRequest(RestRequest request, RestChannel restChannel, XPackClient client) throws Exception { + new XPackUsageRequestBuilder(client.es()).execute(new RestBuilderListener(restChannel) { + @Override + public RestResponse buildResponse(XPackUsageResponse response, XContentBuilder builder) throws Exception { + builder.startObject(); + for (XPackFeatureSet.Usage usage : response.getUsages()) { + builder.field(usage.name(), usage); + } + builder.endObject(); + return new BytesRestResponse(OK, builder); + } + }); + } +} diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java index c39bbec3f94..d57f918469b 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java @@ -7,9 +7,14 @@ package org.elasticsearch.xpack.watcher; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.XPackFeatureSet; +import java.io.IOException; + /** * */ @@ -19,9 +24,10 @@ public class WatcherFeatureSet implements XPackFeatureSet { private final WatcherLicensee licensee; @Inject - public WatcherFeatureSet(Settings settings, @Nullable WatcherLicensee licensee) { + public WatcherFeatureSet(Settings settings, @Nullable WatcherLicensee licensee, NamedWriteableRegistry namedWriteableRegistry) { this.enabled = Watcher.enabled(settings); this.licensee = licensee; + namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); } @Override @@ -43,4 +49,36 @@ public class WatcherFeatureSet implements XPackFeatureSet { public boolean enabled() { return enabled; } + + @Override + public Usage usage() { + return new Usage(available(), enabled()); + } + + static class Usage extends XPackFeatureSet.Usage { + + private static final String WRITEABLE_NAME = writeableName(Watcher.NAME); + + public Usage(StreamInput input) throws IOException { + super(input); + } + + public Usage(boolean available, boolean enabled) { + super(Watcher.NAME, available, enabled); + } + + @Override + public String getWriteableName() { + return WRITEABLE_NAME; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder.startObject() + .field(Field.AVAILABLE, available) + .field(Field.ENABLED, enabled) + .endObject(); + + } + } } From 084179f4572c95b94d6f072eacf39b76aac4d36a Mon Sep 17 00:00:00 2001 From: uboness Date: Wed, 11 May 2016 20:53:16 +0200 Subject: [PATCH 14/16] Added security realm feature usage stats - if active, `file` realm size - if active, `native` realm size - if active, `ldap` realm size, whether SSL is used, load balance type used, user search used - if active, `active_directory` realm size, whether SSL is used, load balance type used `size` is scale estimation based on the local cache. Scales are: `small` (under 10 users), `medium` (under 50 users), `large` (under 250 users) and `x-large` (above 250 users). Original commit: elastic/x-pack-elasticsearch@c6efb17aa4dd3f03856435c8a9f7a3c061480cee --- .../graph/GraphFeatureSetTests.java | 60 +++++++++ .../plugin/LicensesServiceNodeTests.java | 1 + .../org/elasticsearch/marvel/Monitoring.java | 8 +- .../marvel/MonitoringFeatureSet.java | 92 +++++++++----- .../marvel/agent/exporter/ExporterModule.java | 22 ++-- .../marvel/MonitoringFeatureSetTests.java | 62 +++++++++ .../org/elasticsearch/shield/Security.java | 33 ++--- .../shield/SecurityFeatureSet.java | 66 ++++++++-- .../shield/authc/AuthenticationModule.java | 6 + .../org/elasticsearch/shield/authc/Realm.java | 11 ++ .../shield/authc/file/FileRealm.java | 12 +- .../shield/authc/ldap/LdapRealm.java | 14 +- .../authc/ldap/support/AbstractLdapRealm.java | 9 ++ .../authc/ldap/support/LdapLoadBalancing.java | 29 ++--- .../authc/ldap/support/SessionFactory.java | 6 +- .../support/CachingUsernamePasswordRealm.java | 8 ++ .../authc/support/UsernamePasswordRealm.java | 28 ++++ .../shield/SecurityFeatureSetTests.java | 120 ++++++++++++++++++ .../AbstractActiveDirectoryIntegTests.java | 66 ++++++++++ .../ActiveDirectoryRealmTests.java | 1 + .../ActiveDirectoryRealmUsageTests.java | 44 +++++++ .../ActiveDirectorySessionFactoryTests.java | 52 +------- .../shield/authc/file/FileRealmTests.java | 27 +++- .../shield/authc/ldap/LdapRealmTests.java | 39 +++++- .../LdapUserSearchSessionFactoryTests.java | 1 + .../shield/authc/ldap/OpenLdapTests.java | 36 ++++++ .../authc/ldap/support/LDAPServersTests.java | 1 + .../ldap/support/LdapLoadBalancingTests.java | 2 +- .../CachingUsernamePasswordRealmTests.java | 3 +- .../support/UsernamePasswordRealmTests.java | 42 ++++++ .../org/elasticsearch/transport/actions | 1 + .../rest-api-spec/api/xpack.usage.json | 14 ++ .../support/xcontent/XContentSource.java | 6 + .../xpack/watcher/WatcherFeatureSetTests.java | 60 +++++++++ 34 files changed, 838 insertions(+), 144 deletions(-) create mode 100644 elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/GraphFeatureSetTests.java create mode 100644 elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java create mode 100644 elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java create mode 100644 elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/AbstractActiveDirectoryIntegTests.java create mode 100644 elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java create mode 100644 elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java create mode 100644 elasticsearch/x-pack/src/test/resources/rest-api-spec/api/xpack.usage.json create mode 100644 elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java diff --git a/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/GraphFeatureSetTests.java b/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/GraphFeatureSetTests.java new file mode 100644 index 00000000000..6e87584d976 --- /dev/null +++ b/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/GraphFeatureSetTests.java @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.graph; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.test.ESTestCase; +import org.junit.Before; + +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * + */ +public class GraphFeatureSetTests extends ESTestCase { + + private GraphLicensee licensee; + private NamedWriteableRegistry namedWriteableRegistry; + + @Before + public void init() throws Exception { + licensee = mock(GraphLicensee.class); + namedWriteableRegistry = mock(NamedWriteableRegistry.class); + } + + public void testWritableRegistration() throws Exception { + new GraphFeatureSet(Settings.EMPTY, licensee, namedWriteableRegistry); + verify(namedWriteableRegistry).register(eq(GraphFeatureSet.Usage.class), eq("xpack.usage.graph"), anyObject()); + } + + public void testAvailable() throws Exception { + GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licensee, namedWriteableRegistry); + boolean available = randomBoolean(); + when(licensee.isAvailable()).thenReturn(available); + assertThat(featureSet.available(), is(available)); + } + + public void testEnabled() throws Exception { + boolean enabled = randomBoolean(); + Settings.Builder settings = Settings.builder(); + if (enabled) { + if (randomBoolean()) { + settings.put("xpack.graph.enabled", enabled); + } + } else { + settings.put("xpack.graph.enabled", enabled); + } + GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licensee, namedWriteableRegistry); + assertThat(featureSet.enabled(), is(enabled)); + } + +} diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/LicensesServiceNodeTests.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/LicensesServiceNodeTests.java index 7e25666ff94..9ac18c44d95 100644 --- a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/LicensesServiceNodeTests.java +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/LicensesServiceNodeTests.java @@ -23,6 +23,7 @@ import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST; */ @ESIntegTestCase.ClusterScope(scope = TEST, numDataNodes = 10, numClientNodes = 0) public class LicensesServiceNodeTests extends AbstractLicensesIntegrationTestCase { + @Override protected Settings nodeSettings(int nodeOrdinal) { return Settings.builder() diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/Monitoring.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/Monitoring.java index bc41c277e00..8b29f92ffa5 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/Monitoring.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/Monitoring.java @@ -46,7 +46,7 @@ public class Monitoring { public Monitoring(Settings settings) { this.settings = settings; - this.enabled = MonitoringSettings.ENABLED.get(settings); + this.enabled = enabled(settings); this.transportClientMode = XPackPlugin.transportClientMode(settings); this.tribeNode = XPackPlugin.isTribeNode(settings); } @@ -62,9 +62,9 @@ public class Monitoring { public Collection nodeModules() { List modules = new ArrayList<>(); modules.add(new MonitoringModule(enabled, transportClientMode)); + modules.add(new ExporterModule(settings)); if (enabled && transportClientMode == false && tribeNode == false) { modules.add(new CollectorModule()); - modules.add(new ExporterModule(settings)); modules.add(new MonitoringClientModule()); } return modules; @@ -100,4 +100,8 @@ public class Monitoring { module.registerLazyInitializable(MonitoringClientProxy.class); } } + + public static boolean enabled(Settings settings) { + return MonitoringSettings.ENABLED.get(settings); + } } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java index 9ba1777b806..7d528bb9f12 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java @@ -10,7 +10,9 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.marvel.agent.exporter.Exporter; import org.elasticsearch.marvel.agent.exporter.Exporters; @@ -27,10 +29,10 @@ public class MonitoringFeatureSet implements XPackFeatureSet { private final boolean enabled; private final MonitoringLicensee licensee; - private final Exporters exporters; + private final org.elasticsearch.marvel.agent.exporter.Exporters exporters; @Inject - public MonitoringFeatureSet(Settings settings, @Nullable MonitoringLicensee licensee, Exporters exporters, + public MonitoringFeatureSet(Settings settings, @Nullable MonitoringLicensee licensee, @Nullable Exporters exporters, NamedWriteableRegistry namedWriteableRegistry) { this.enabled = MonitoringSettings.ENABLED.get(settings); this.licensee = licensee; @@ -60,48 +62,48 @@ public class MonitoringFeatureSet implements XPackFeatureSet { @Override public Usage usage() { + return new Usage(available(), enabled(), exportersUsage(exporters)); + } - int enabledLocalExporters = 0; - int enabledHttpExporters = 0; - int enabledUnknownExporters = 0; + static Usage.Exporters exportersUsage(Exporters exporters) { + if (exporters == null) { + return null; + } + int local = 0; + int http = 0; + int unknown = 0; for (Exporter exporter : exporters) { if (exporter.config().enabled()) { switch (exporter.type()) { case LocalExporter.TYPE: - enabledLocalExporters++; + local++; break; case HttpExporter.TYPE: - enabledHttpExporters++; + http++; break; default: - enabledUnknownExporters++; + unknown++; } } } - - return new Usage(available(), enabled(), enabledLocalExporters, enabledHttpExporters, enabledUnknownExporters); + return new Usage.Exporters(local, http, unknown); } static class Usage extends XPackFeatureSet.Usage { private static String WRITEABLE_NAME = writeableName(Monitoring.NAME); - private final int enabledLocalExporters; - private final int enabledHttpExporters; - private final int enabledUnknownExporters; + private @Nullable + Exporters exporters; public Usage(StreamInput in) throws IOException { super(in); - this.enabledLocalExporters = in.readVInt(); - this.enabledHttpExporters = in.readVInt(); - this.enabledUnknownExporters = in.readVInt(); + exporters = new Exporters(in); } - public Usage(boolean available, boolean enabled, int enabledLocalExporters, int enabledHttpExporters, int enabledUnknownExporters) { + public Usage(boolean available, boolean enabled, Exporters exporters) { super(Monitoring.NAME, available, enabled); - this.enabledLocalExporters = enabledLocalExporters; - this.enabledHttpExporters = enabledHttpExporters; - this.enabledUnknownExporters = enabledUnknownExporters; + this.exporters = exporters; } @Override @@ -122,9 +124,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet { @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - out.writeVInt(enabledLocalExporters); - out.writeVInt(enabledHttpExporters); - out.writeVInt(enabledUnknownExporters); + out.writeOptionalWriteable(exporters); } @Override @@ -132,18 +132,47 @@ public class MonitoringFeatureSet implements XPackFeatureSet { builder.startObject(); builder.field(Field.AVAILABLE, available); builder.field(Field.ENABLED, enabled); - - builder.startObject(Field.ENABLED_EXPORTERS); - builder.field(Field.LOCAL, enabledLocalExporters); - builder.field(Field.HTTP, enabledHttpExporters); - if (enabledUnknownExporters > 0) { - builder.field(Field.UNKNOWN, enabledUnknownExporters); + if (exporters != null) { + builder.field(Field.ENABLED_EXPORTERS, exporters); } - builder.endObject(); - return builder.endObject(); } + static class Exporters implements Writeable, ToXContent { + + private final int enabledLocalExporters; + private final int enabledHttpExporters; + private final int enabledUnknownExporters; + + public Exporters(StreamInput in) throws IOException { + this(in.readVInt(), in.readVInt(), in.readVInt()); + } + + public Exporters(int enabledLocalExporters, int enabledHttpExporters, int enabledUnknownExporters) { + this.enabledLocalExporters = enabledLocalExporters; + this.enabledHttpExporters = enabledHttpExporters; + this.enabledUnknownExporters = enabledUnknownExporters; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeVInt(enabledLocalExporters); + out.writeVInt(enabledHttpExporters); + out.writeVInt(enabledUnknownExporters); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(Field.LOCAL, enabledLocalExporters); + builder.field(Field.HTTP, enabledHttpExporters); + if (enabledUnknownExporters > 0) { + builder.field(Field.UNKNOWN, enabledUnknownExporters); + } + return builder.endObject(); + } + } + interface Field extends XPackFeatureSet.Usage.Field { String ENABLED_EXPORTERS = "enabled_exporters"; String LOCAL = "_local"; @@ -151,4 +180,5 @@ public class MonitoringFeatureSet implements XPackFeatureSet { String UNKNOWN = "_unknown"; } } + } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/ExporterModule.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/ExporterModule.java index 4940a980181..26fb2cea463 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/ExporterModule.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/agent/exporter/ExporterModule.java @@ -7,18 +7,20 @@ package org.elasticsearch.marvel.agent.exporter; import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.multibindings.MapBinder; +import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.marvel.Monitoring; import org.elasticsearch.marvel.agent.exporter.http.HttpExporter; import org.elasticsearch.marvel.agent.exporter.local.LocalExporter; +import org.elasticsearch.xpack.XPackPlugin; import java.util.HashMap; import java.util.Map; public class ExporterModule extends AbstractModule { - private final Map>> exporterFactories = new HashMap<>(); - private final Settings settings; + private final Map>> exporterFactories = new HashMap<>(); public ExporterModule(Settings settings) { this.settings = settings; @@ -28,13 +30,17 @@ public class ExporterModule extends AbstractModule { @Override protected void configure() { - bind(Exporters.class).asEagerSingleton(); - MapBinder factoryBinder = MapBinder.newMapBinder(binder(), String.class, Exporter.Factory.class); - for (Map.Entry>> entry : exporterFactories.entrySet()) { - bind(entry.getValue()).asEagerSingleton(); - factoryBinder.addBinding(entry.getKey()).to(entry.getValue()); + if (Monitoring.enabled(settings) && XPackPlugin.transportClientMode(settings) == false + && XPackPlugin.isTribeNode(settings) == false) { + bind(Exporters.class).asEagerSingleton(); + MapBinder factoryBinder = MapBinder.newMapBinder(binder(), String.class, Exporter.Factory.class); + for (Map.Entry>> entry : exporterFactories.entrySet()) { + bind(entry.getValue()).asEagerSingleton(); + factoryBinder.addBinding(entry.getKey()).to(entry.getValue()); + } + } else { + bind(Exporters.class).toProvider(Providers.of(null)); } - } public void registerExporter(String type, Class> factory) { diff --git a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java new file mode 100644 index 00000000000..84f37f47fd2 --- /dev/null +++ b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.marvel; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.marvel.agent.exporter.Exporters; +import org.elasticsearch.test.ESTestCase; +import org.junit.Before; + +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * + */ +public class MonitoringFeatureSetTests extends ESTestCase { + + private MonitoringLicensee licensee; + private NamedWriteableRegistry namedWriteableRegistry; + private Exporters exporters; + + @Before + public void init() throws Exception { + licensee = mock(MonitoringLicensee.class); + exporters = mock(Exporters.class); + namedWriteableRegistry = mock(NamedWriteableRegistry.class); + } + + public void testWritableRegistration() throws Exception { + new MonitoringFeatureSet(Settings.EMPTY, licensee, exporters, namedWriteableRegistry); + verify(namedWriteableRegistry).register(eq(MonitoringFeatureSet.Usage.class), eq("xpack.usage.monitoring"), anyObject()); + } + + public void testAvailable() throws Exception { + MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licensee, exporters, namedWriteableRegistry); + boolean available = randomBoolean(); + when(licensee.available()).thenReturn(available); + assertThat(featureSet.available(), is(available)); + } + + public void testEnabled() throws Exception { + boolean enabled = randomBoolean(); + Settings.Builder settings = Settings.builder(); + if (enabled) { + if (randomBoolean()) { + settings.put("xpack.monitoring.enabled", enabled); + } + } else { + settings.put("xpack.monitoring.enabled", enabled); + } + MonitoringFeatureSet featureSet = new MonitoringFeatureSet(settings.build(), licensee, exporters, namedWriteableRegistry); + assertThat(featureSet.enabled(), is(enabled)); + } +} diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/Security.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/Security.java index f4476b4f78c..6d63c016a03 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/Security.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/Security.java @@ -73,8 +73,8 @@ import org.elasticsearch.shield.rest.action.user.RestChangePasswordAction; import org.elasticsearch.shield.rest.action.user.RestDeleteUserAction; import org.elasticsearch.shield.rest.action.user.RestGetUsersAction; import org.elasticsearch.shield.rest.action.user.RestPutUserAction; -import org.elasticsearch.shield.ssl.SSLModule; import org.elasticsearch.shield.ssl.SSLConfiguration; +import org.elasticsearch.shield.ssl.SSLModule; import org.elasticsearch.shield.support.OptionalSettings; import org.elasticsearch.shield.transport.ShieldClientTransportService; import org.elasticsearch.shield.transport.ShieldServerTransportService; @@ -125,27 +125,28 @@ public class Security { public Collection nodeModules() { List modules = new ArrayList<>(); - // we can't load that at construction time since the license plugin might not have been loaded at that point - // which might not be the case during Plugin class instantiation. Once nodeModules are pulled - // everything should have been loaded - if (enabled && transportClientMode == false) { - securityLicenseState = new SecurityLicenseState(); - } - - modules.add(new SecurityModule(settings, securityLicenseState)); - - if (enabled == false) { - return modules; - } - - if (transportClientMode == true) { + if (transportClientMode) { + if (enabled == false) { + return modules; + } + modules.add(new SecurityModule(settings, securityLicenseState)); modules.add(new ShieldTransportModule(settings)); modules.add(new SSLModule(settings)); return modules; } - modules.add(new CryptoModule(settings)); modules.add(new AuthenticationModule(settings)); + if (enabled == false) { + modules.add(new SecurityModule(settings, securityLicenseState)); + return modules; + } + + // we can't load that at construction time since the license plugin might not have been loaded at that point + // which might not be the case during Plugin class instantiation. Once nodeModules are pulled + // everything should have been loaded + securityLicenseState = new SecurityLicenseState(); + modules.add(new SecurityModule(settings, securityLicenseState)); + modules.add(new CryptoModule(settings)); modules.add(new AuthorizationModule(settings)); modules.add(new AuditTrailModule(settings)); modules.add(new ShieldRestModule(settings)); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java index 6a53e72eb52..07eb6c86cf0 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java @@ -9,12 +9,21 @@ import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.marvel.Monitoring; +import org.elasticsearch.shield.authc.Realm; +import org.elasticsearch.shield.authc.Realms; +import org.elasticsearch.shield.authc.esnative.ReservedRealm; import org.elasticsearch.xpack.XPackFeatureSet; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @@ -23,12 +32,14 @@ public class SecurityFeatureSet implements XPackFeatureSet { private final boolean enabled; private final SecurityLicenseState licenseState; + private final @Nullable Realms realms; @Inject public SecurityFeatureSet(Settings settings, @Nullable SecurityLicenseState licenseState, - NamedWriteableRegistry namedWriteableRegistry) { + @Nullable Realms realms, NamedWriteableRegistry namedWriteableRegistry) { this.enabled = Security.enabled(settings); this.licenseState = licenseState; + this.realms = realms; namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); } @@ -53,20 +64,39 @@ public class SecurityFeatureSet implements XPackFeatureSet { } @Override - public XPackFeatureSet.Usage usage() { - return new Usage(available(), enabled()); + public Usage usage() { + List> enabledRealms = buildEnabledRealms(realms); + return new Usage(available(), enabled(), enabledRealms); + } + + static List> buildEnabledRealms(Realms realms) { + if (realms == null) { + return Collections.emptyList(); + } + List> enabledRealms = new ArrayList<>(); + for (Realm realm : realms) { + if (realm instanceof ReservedRealm) { + continue; // we don't need usage of this one + } + Map stats = realm.usageStats(); + enabledRealms.add(stats); + } + return enabledRealms; } static class Usage extends XPackFeatureSet.Usage { private static final String WRITEABLE_NAME = writeableName(Security.NAME); + private List> enabledRealms; - public Usage(StreamInput input) throws IOException { - super(input); + public Usage(StreamInput in) throws IOException { + super(in); + enabledRealms = in.readList(StreamInput::readMap); } - public Usage(boolean available, boolean enabled) { + public Usage(boolean available, boolean enabled, List> enabledRealms) { super(Security.NAME, available, enabled); + this.enabledRealms = enabledRealms; } @Override @@ -75,12 +105,24 @@ public class SecurityFeatureSet implements XPackFeatureSet { } @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return builder.startObject() - .field(Field.AVAILABLE, available) - .field(Field.ENABLED, enabled) - .endObject(); + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeList(enabledRealms.stream().map((m) -> (Writeable) o -> o.writeMap(m)).collect(Collectors.toList())); + } + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + builder.field(Field.AVAILABLE, available); + builder.field(Field.ENABLED, enabled); + if (enabled) { + builder.field(Field.ENABLED_REALMS, enabledRealms); + } + return builder.endObject(); + } + + interface Field extends XPackFeatureSet.Usage.Field { + String ENABLED_REALMS = "enabled_realms"; } } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java index 5b0cc1186eb..5751aed66d0 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java @@ -6,6 +6,7 @@ package org.elasticsearch.shield.authc; import org.elasticsearch.common.inject.multibindings.MapBinder; +import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.authc.activedirectory.ActiveDirectoryRealm; import org.elasticsearch.shield.authc.esnative.NativeRealm; @@ -42,6 +43,11 @@ public class AuthenticationModule extends AbstractShieldModule.Node { @Override protected void configureNode() { + if (!shieldEnabled) { + bind(Realms.class).toProvider(Providers.of(null)); + return; + } + AnonymousUser.initialize(settings); MapBinder mapBinder = MapBinder.newMapBinder(binder(), String.class, Realm.Factory.class); mapBinder.addBinding(FileRealm.TYPE).to(FileRealm.Factory.class).asEagerSingleton(); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java index 37618f3cb28..b9aac447ac0 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/Realm.java @@ -9,6 +9,9 @@ import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.shield.user.User; +import java.util.HashMap; +import java.util.Map; + /** * An authentication mechanism to which the default authentication {@link org.elasticsearch.shield.authc.AuthenticationService service} * delegates the authentication process. Different realms may be defined, each may be based on different @@ -84,6 +87,14 @@ public abstract class Realm implements Comparable */ public abstract User lookupUser(String username); + public Map usageStats() { + Map stats = new HashMap<>(); + stats.put("type", type); + stats.put("name", name()); + stats.put("order", order()); + return stats; + } + /** * Indicates whether this realm supports user lookup. * @return true if the realm supports user lookup diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java index 9f7982ed1cb..473cc11bffc 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java @@ -9,14 +9,16 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.rest.RestController; -import org.elasticsearch.shield.user.User; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.shield.authc.support.RefreshListener; import org.elasticsearch.shield.authc.support.UsernamePasswordRealm; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; +import org.elasticsearch.shield.user.User; import org.elasticsearch.watcher.ResourceWatcherService; +import java.util.Map; + /** * */ @@ -55,6 +57,14 @@ public class FileRealm extends CachingUsernamePasswordRealm { return null; } + @Override + public Map usageStats() { + Map stats = super.usageStats(); + // here we can determine the size based on the in mem user store + stats.put("size", UserbaseScale.resolve(userPasswdStore.usersCount())); + return stats; + } + @Override public boolean userLookupSupported() { return true; diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java index c8e6d401251..02abc0843db 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java @@ -17,6 +17,7 @@ import org.elasticsearch.shield.ssl.ClientSSLService; import org.elasticsearch.watcher.ResourceWatcherService; import java.io.IOException; +import java.util.Map; /** * Authenticates username/password tokens against ldap, locates groups and maps them to roles. @@ -29,6 +30,13 @@ public class LdapRealm extends AbstractLdapRealm { super(TYPE, config, ldap, roleMapper); } + @Override + public Map usageStats() { + Map stats = super.usageStats(); + stats.put("user_search", Factory.userSearchSettings(config).isEmpty() == false); + return stats; + } + public static class Factory extends AbstractLdapRealm.Factory { private final ResourceWatcherService watcherService; @@ -53,7 +61,7 @@ public class LdapRealm extends AbstractLdapRealm { } static SessionFactory sessionFactory(RealmConfig config, ClientSSLService clientSSLService) throws IOException { - Settings searchSettings = config.settings().getAsSettings("user_search"); + Settings searchSettings = userSearchSettings(config); if (!searchSettings.names().isEmpty()) { if (config.settings().getAsArray(LdapSessionFactory.USER_DN_TEMPLATES_SETTING).length > 0) { throw new IllegalArgumentException("settings were found for both user search and user template modes of operation. " + @@ -64,5 +72,9 @@ public class LdapRealm extends AbstractLdapRealm { } return new LdapSessionFactory(config, clientSSLService).init(); } + + static Settings userSearchSettings(RealmConfig config) { + return config.settings().getAsSettings("user_search"); + } } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java index 01ff5c9dede..c327a8d0d24 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/AbstractLdapRealm.java @@ -15,6 +15,7 @@ import org.elasticsearch.shield.authc.support.UsernamePasswordRealm; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -65,6 +66,14 @@ public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm { return sessionFactory.supportsUnauthenticatedSession(); } + @Override + public Map usageStats() { + Map usage = super.usageStats(); + usage.put("load_balance_type", LdapLoadBalancing.resolve(config.settings()).toString()); + usage.put("ssl", sessionFactory.sslUsed); + return usage; + } + private void logException(String action, Exception e, String principal) { if (logger.isDebugEnabled()) { logger.debug("{} failed for user [{}]", e, action, principal); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancing.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancing.java index e9b455f1200..f0454530099 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancing.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancing.java @@ -16,7 +16,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import javax.net.SocketFactory; -import java.util.Arrays; import java.util.Locale; /** @@ -83,25 +82,23 @@ public enum LdapLoadBalancing { @Override public String toString() { - return name().toLowerCase(Locale.ENGLISH); + return name().toLowerCase(Locale.ROOT); + } + + public static LdapLoadBalancing resolve(Settings settings) { + Settings loadBalanceSettings = settings.getAsSettings(LOAD_BALANCE_SETTINGS); + String type = loadBalanceSettings.get(LOAD_BALANCE_TYPE_SETTING, LOAD_BALANCE_TYPE_DEFAULT); + try { + return valueOf(type.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException ilae) { + throw new IllegalArgumentException("unknown load balance type [" + type + "]", ilae); + } } public static ServerSet serverSet(String[] addresses, int[] ports, Settings settings, @Nullable SocketFactory socketFactory, @Nullable LDAPConnectionOptions options) { + LdapLoadBalancing loadBalancing = resolve(settings); Settings loadBalanceSettings = settings.getAsSettings(LOAD_BALANCE_SETTINGS); - String type = loadBalanceSettings.get(LOAD_BALANCE_TYPE_SETTING, LOAD_BALANCE_TYPE_DEFAULT); - switch (type.toLowerCase(Locale.ENGLISH)) { - case "failover": - return FAILOVER.buildServerSet(addresses, ports, loadBalanceSettings, socketFactory, options); - case "dns_failover": - return DNS_FAILOVER.buildServerSet(addresses, ports, loadBalanceSettings, socketFactory, options); - case "round_robin": - return ROUND_ROBIN.buildServerSet(addresses, ports, loadBalanceSettings, socketFactory, options); - case "dns_round_robin": - return DNS_ROUND_ROBIN.buildServerSet(addresses, ports, loadBalanceSettings, socketFactory, options); - default: - throw new IllegalArgumentException("unknown server set type [" + type + "]. value must be one of " + - Arrays.toString(LdapLoadBalancing.values())); - } + return loadBalancing.buildServerSet(addresses, ports, loadBalanceSettings, socketFactory, options); } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/SessionFactory.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/SessionFactory.java index 907abfccf95..af82cb43545 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/SessionFactory.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/ldap/support/SessionFactory.java @@ -52,7 +52,9 @@ public abstract class SessionFactory { protected final RealmConfig config; protected final TimeValue timeout; protected final ClientSSLService sslService; + protected ServerSet serverSet; + protected boolean sslUsed; protected SessionFactory(RealmConfig config, ClientSSLService sslService) { this.config = config; @@ -118,7 +120,9 @@ public abstract class SessionFactory { } public T init() { - this.serverSet = serverSet(config.settings(), sslService, ldapServers(config.settings())); + LDAPServers ldapServers = ldapServers(config.settings()); + this.serverSet = serverSet(config.settings(), sslService, ldapServers); + this.sslUsed = ldapServers.ssl; return (T) this; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java index af61e98718e..a977be5f7e1 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java @@ -14,6 +14,7 @@ import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.support.Exceptions; import org.elasticsearch.shield.user.User; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -164,6 +165,13 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm } } + @Override + public Map usageStats() { + Map stats = super.usageStats(); + stats.put("size", UserbaseScale.resolve(cache.count()).toString()); + return stats; + } + protected abstract User doAuthenticate(UsernamePasswordToken token); protected abstract User doLookupUser(String username); diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java index 0a069867b72..1b7138f7845 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java @@ -11,6 +11,8 @@ import org.elasticsearch.shield.authc.AuthenticationToken; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.RealmConfig; +import java.util.Locale; + /** * */ @@ -36,4 +38,30 @@ public abstract class UsernamePasswordRealm extends Realm restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); } } + + public enum UserbaseScale { + + SMALL, + MEDIUM, + LARGE, + XLARGE; + + public static UserbaseScale resolve(int count) { + if (count < 10) { + return SMALL; + } + if (count < 50) { + return MEDIUM; + } + if (count < 250) { + return LARGE; + } + return XLARGE; + } + + @Override + public String toString() { + return this == XLARGE ? "x-large" : name().toLowerCase(Locale.ROOT); + } + } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java new file mode 100644 index 00000000000..f07afb60f88 --- /dev/null +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.shield; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.shield.authc.Realm; +import org.elasticsearch.shield.authc.Realms; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; +import org.junit.Before; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * + */ +public class SecurityFeatureSetTests extends ESTestCase { + + private SecurityLicenseState licenseState; + private Realms realms; + private NamedWriteableRegistry namedWriteableRegistry; + + @Before + public void init() throws Exception { + licenseState = mock(SecurityLicenseState.class); + realms = mock(Realms.class); + namedWriteableRegistry = mock(NamedWriteableRegistry.class); + } + + public void testWritableRegistration() throws Exception { + new SecurityFeatureSet(Settings.EMPTY, licenseState, realms, namedWriteableRegistry); + verify(namedWriteableRegistry).register(eq(SecurityFeatureSet.Usage.class), eq("xpack.usage.security"), anyObject()); + } + + public void testAvailable() throws Exception { + SecurityFeatureSet featureSet = new SecurityFeatureSet(Settings.EMPTY, licenseState, realms, namedWriteableRegistry); + boolean available = randomBoolean(); + when(licenseState.authenticationAndAuthorizationEnabled()).thenReturn(available); + assertThat(featureSet.available(), is(available)); + } + + public void testEnabled() throws Exception { + boolean enabled = randomBoolean(); + Settings.Builder settings = Settings.builder(); + if (enabled) { + if (randomBoolean()) { + settings.put("xpack.security.enabled", enabled); + } + } else { + settings.put("xpack.security.enabled", enabled); + } + SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState, realms, namedWriteableRegistry); + assertThat(featureSet.enabled(), is(enabled)); + } + + public void testUsage() throws Exception { + + boolean available = randomBoolean(); + when(licenseState.authenticationAndAuthorizationEnabled()).thenReturn(available); + + Settings.Builder settings = Settings.builder(); + + boolean enabled = randomBoolean(); + if (enabled) { + if (randomBoolean()) { + settings.put("xpack.security.enabled", enabled); + } + } else { + settings.put("xpack.security.enabled", enabled); + } + + List realmsList= new ArrayList<>(); + + for (int i = 0; i < 5; i++) { + Realm realm = mock(Realm.class); + when(realm.type()).thenReturn("type" + i); + realmsList.add(realm); + Map realmUsage = new HashMap<>(); + realmUsage.put("key1", "value" + i); + realmUsage.put("key2", i); + realmUsage.put("key3", i % 2 == 0); + when(realm.usageStats()).thenReturn(realmUsage); + } + when(realms.iterator()).thenReturn(realmsList.iterator()); + + SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState, realms, namedWriteableRegistry); + SecurityFeatureSet.Usage usage = featureSet.usage(); + assertThat(usage, is(notNullValue())); + assertThat(usage.name(), is(Security.NAME)); + assertThat(usage.enabled(), is(enabled)); + assertThat(usage.available(), is(available)); + XContentSource source = new XContentSource(usage); + + if (enabled) { + for (int i = 0; i < 5; i++) { + assertThat(source.getValue("enabled_realms." + i + ".key1"), is("value" + i)); + assertThat(source.getValue("enabled_realms." + i + ".key2"), is(i)); + assertThat(source.getValue("enabled_realms." + i + ".key3"), is(i % 2 == 0)); + } + } else { + assertThat(source.getValue("enabled_realms"), is(nullValue())); + } + } +} diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/AbstractActiveDirectoryIntegTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/AbstractActiveDirectoryIntegTests.java new file mode 100644 index 00000000000..f08785b1477 --- /dev/null +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/AbstractActiveDirectoryIntegTests.java @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.shield.authc.activedirectory; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.env.Environment; +import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope; +import org.elasticsearch.shield.ssl.ClientSSLService; +import org.elasticsearch.shield.ssl.SSLConfiguration.Global; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.junit.annotations.Network; +import org.junit.Before; + +import java.nio.file.Path; + +@Network +public class AbstractActiveDirectoryIntegTests extends ESTestCase { + + public static final String AD_LDAP_URL = "ldaps://54.213.145.20:636"; + public static final String PASSWORD = "NickFuryHeartsES"; + public static final String AD_DOMAIN = "ad.test.elasticsearch.com"; + + protected ClientSSLService clientSSLService; + protected Settings globalSettings; + protected boolean useGlobalSSL; + + @Before + public void initializeSslSocketFactory() throws Exception { + useGlobalSSL = randomBoolean(); + Path keystore = getDataPath("../ldap/support/ldaptrust.jks"); + /* + * Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext. + * If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname + * verification tests since a re-established connection does not perform hostname verification. + */ + Settings.Builder builder = Settings.builder().put("path.home", createTempDir()); + if (useGlobalSSL) { + builder.put("xpack.security.ssl.keystore.path", keystore) + .put("xpack.security.ssl.keystore.password", "changeit"); + } else { + builder.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false); + } + globalSettings = builder.build(); + Environment environment = new Environment(globalSettings); + clientSSLService = new ClientSSLService(globalSettings, new Global(globalSettings)); + clientSSLService.setEnvironment(environment); + } + + Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN, LdapSearchScope scope, + boolean hostnameVerification) { + Settings.Builder builder = Settings.builder() + .putArray(ActiveDirectorySessionFactory.URLS_SETTING, ldapUrl) + .put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName) + .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN) + .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_SCOPE_SETTING, scope) + .put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); + if (useGlobalSSL == false) { + builder.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks")) + .put("ssl.truststore.password", "changeit"); + } + return builder.build(); + } +} diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmTests.java index 302d716679f..547807fc2cd 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmTests.java @@ -57,6 +57,7 @@ import static org.mockito.Mockito.verify; * additional bind DN with a password in the test setup since it really is not a DN in the ldif file */ public class ActiveDirectoryRealmTests extends ESTestCase { + private static final String PASSWORD = "password"; protected static int numberOfLdapServers; diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java new file mode 100644 index 00000000000..2eeb5ad9dd6 --- /dev/null +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.shield.authc.activedirectory; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.shield.authc.RealmConfig; +import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope; +import org.elasticsearch.shield.authc.support.DnRoleMapper; +import org.elasticsearch.test.junit.annotations.Network; + +import java.util.Map; + +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.Mockito.mock; + +@Network +public class ActiveDirectoryRealmUsageTests extends AbstractActiveDirectoryIntegTests { + + public void testUsageStats() throws Exception { + String loadBalanceType = randomFrom("failover", "round_robin"); + Settings settings = Settings.builder() + .put(buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Bruce Banner, CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com", + LdapSearchScope.BASE, false)) + .put("load_balance.type", loadBalanceType) + .build(); + RealmConfig config = new RealmConfig("ad-test", settings, globalSettings); + ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, clientSSLService).init(); + ActiveDirectoryRealm realm = new ActiveDirectoryRealm(config, sessionFactory, mock(DnRoleMapper.class)); + + Map stats = realm.usageStats(); + assertThat(stats, is(notNullValue())); + assertThat(stats, hasEntry("type", "active_directory")); + assertThat(stats, hasEntry("name", "ad-test")); + assertThat(stats, hasEntry("order", realm.order())); + assertThat(stats, hasEntry("size", "small")); + assertThat(stats, hasEntry("ssl", true)); + assertThat(stats, hasEntry("load_balance_type", loadBalanceType)); + } +} diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectorySessionFactoryTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectorySessionFactoryTests.java index 5323d136e02..491f980083a 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectorySessionFactoryTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectorySessionFactoryTests.java @@ -7,7 +7,6 @@ package org.elasticsearch.shield.authc.activedirectory; import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.ldap.LdapSessionFactory; import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope; @@ -15,14 +14,9 @@ import org.elasticsearch.shield.authc.ldap.support.LdapSession; import org.elasticsearch.shield.authc.ldap.support.LdapTestCase; import org.elasticsearch.shield.authc.ldap.support.SessionFactory; import org.elasticsearch.shield.authc.support.SecuredStringTests; -import org.elasticsearch.shield.ssl.ClientSSLService; -import org.elasticsearch.shield.ssl.SSLConfiguration.Global; -import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.junit.annotations.Network; -import org.junit.Before; import java.io.IOException; -import java.nio.file.Path; import java.util.List; import static org.elasticsearch.test.ShieldTestsUtils.assertAuthenticationException; @@ -32,36 +26,7 @@ import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; @Network -public class ActiveDirectorySessionFactoryTests extends ESTestCase { - public static final String AD_LDAP_URL = "ldaps://54.213.145.20:636"; - public static final String PASSWORD = "NickFuryHeartsES"; - public static final String AD_DOMAIN = "ad.test.elasticsearch.com"; - - private ClientSSLService clientSSLService; - private Settings globalSettings; - private boolean useGlobalSSL; - - @Before - public void initializeSslSocketFactory() throws Exception { - useGlobalSSL = randomBoolean(); - Path keystore = getDataPath("../ldap/support/ldaptrust.jks"); - /* - * Prior to each test we reinitialize the socket factory with a new SSLService so that we get a new SSLContext. - * If we re-use a SSLContext, previously connected sessions can get re-established which breaks hostname - * verification tests since a re-established connection does not perform hostname verification. - */ - Settings.Builder builder = Settings.builder().put("path.home", createTempDir()); - if (useGlobalSSL) { - builder.put("xpack.security.ssl.keystore.path", keystore) - .put("xpack.security.ssl.keystore.password", "changeit"); - } else { - builder.put(Global.AUTO_GENERATE_SSL_SETTING.getKey(), false); - } - globalSettings = builder.build(); - Environment environment = new Environment(globalSettings); - clientSSLService = new ClientSSLService(globalSettings, new Global(globalSettings)); - clientSSLService.setEnvironment(environment); - } +public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryIntegTests { @SuppressWarnings("unchecked") public void testAdAuth() throws Exception { @@ -333,19 +298,4 @@ public class ActiveDirectorySessionFactoryTests extends ESTestCase { } return builder.build(); } - - Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN, LdapSearchScope scope, - boolean hostnameVerification) { - Settings.Builder builder = Settings.builder() - .putArray(ActiveDirectorySessionFactory.URLS_SETTING, ldapUrl) - .put(ActiveDirectorySessionFactory.AD_DOMAIN_NAME_SETTING, adDomainName) - .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN) - .put(ActiveDirectorySessionFactory.AD_USER_SEARCH_SCOPE_SETTING, scope) - .put(ActiveDirectorySessionFactory.HOSTNAME_VERIFICATION_SETTING, hostnameVerification); - if (useGlobalSSL == false) { - builder.put("ssl.truststore.path", getDataPath("../ldap/support/ldaptrust.jks")) - .put("ssl.truststore.password", "changeit"); - } - return builder.build(); - } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java index db562447d42..e1c42bc5775 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java @@ -7,23 +7,25 @@ package org.elasticsearch.shield.authc.file; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.shield.user.User; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.SecuredStringTests; +import org.elasticsearch.shield.authc.support.UsernamePasswordRealm; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; +import org.elasticsearch.shield.user.User; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.watcher.ResourceWatcherService; import org.junit.Before; import java.util.Locale; +import java.util.Map; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -161,6 +163,27 @@ public class FileRealmTests extends ESTestCase { assertThat(user5, sameInstance(user6)); } + public void testUsageStats() throws Exception { + int userCount = randomIntBetween(0, 1000); + when(userPasswdStore.usersCount()).thenReturn(userCount); + + Settings.Builder settings = Settings.builder(); + + int order = randomIntBetween(0, 10); + settings.put("order", order); + + RealmConfig config = new RealmConfig("file-realm", settings.build(), globalSettings); + FileRealm realm = new FileRealm(config, userPasswdStore, userRolesStore); + + Map usage = realm.usageStats(); + assertThat(usage, is(notNullValue())); + assertThat(usage, hasEntry("type", "file")); + assertThat(usage, hasEntry("name", "file-realm")); + assertThat(usage, hasEntry("order", order)); + assertThat(usage, hasEntry("size", UsernamePasswordRealm.UserbaseScale.resolve(userCount))); + + } + static class UserPasswdStore extends FileUserPasswdStore { public UserPasswdStore(RealmConfig config) { super(config, mock(ResourceWatcherService.class)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java index 02c9cbcd33e..409ae31c7d0 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java @@ -6,7 +6,6 @@ package org.elasticsearch.shield.authc.ldap; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.shield.user.User; import org.elasticsearch.shield.authc.RealmConfig; import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope; import org.elasticsearch.shield.authc.ldap.support.LdapTestCase; @@ -15,16 +14,20 @@ import org.elasticsearch.shield.authc.support.DnRoleMapper; import org.elasticsearch.shield.authc.support.SecuredString; import org.elasticsearch.shield.authc.support.SecuredStringTests; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; +import org.elasticsearch.shield.user.User; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; import org.junit.After; import org.junit.Before; +import java.util.Map; + import static org.elasticsearch.shield.authc.ldap.LdapSessionFactory.USER_DN_TEMPLATES_SETTING; import static org.elasticsearch.shield.authc.ldap.support.SessionFactory.HOSTNAME_VERIFICATION_SETTING; import static org.elasticsearch.shield.authc.ldap.support.SessionFactory.URLS_SETTING; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -35,6 +38,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; public class LdapRealmTests extends LdapTestCase { + public static final String VALID_USER_TEMPLATE = "cn={0},ou=people,o=sevenSeas"; public static final String VALID_USERNAME = "Thomas Masterman Hardy"; public static final String PASSWORD = "pass"; @@ -217,4 +221,37 @@ public class LdapRealmTests extends LdapTestCase { assertThat(user, notNullValue()); assertThat(user.roles(), arrayContaining("avenger")); } + + public void testUsageStats() throws Exception { + String groupSearchBase = "o=sevenSeas"; + Settings.Builder settings = Settings.builder() + .putArray(URLS_SETTING, ldapUrls()) + .put("bind_dn", "cn=Thomas Masterman Hardy,ou=people,o=sevenSeas") + .put("bind_password", PASSWORD) + .put("group_search.base_dn", groupSearchBase) + .put("group_search.scope", LdapSearchScope.SUB_TREE) + .put(HOSTNAME_VERIFICATION_SETTING, false); + + int order = randomIntBetween(0, 10); + settings.put("order", order); + + boolean userSearch = randomBoolean(); + if (userSearch) { + settings.put("user_search.base_dn", ""); + } + + RealmConfig config = new RealmConfig("ldap-realm", settings.build(), globalSettings); + + LdapSessionFactory ldapFactory = new LdapSessionFactory(config, null).init(); + LdapRealm realm = new LdapRealm(config, ldapFactory, new DnRoleMapper(LdapRealm.TYPE, config, resourceWatcherService, null)); + + Map stats = realm.usageStats(); + assertThat(stats, is(notNullValue())); + assertThat(stats, hasEntry("type", "ldap")); + assertThat(stats, hasEntry("name", "ldap-realm")); + assertThat(stats, hasEntry("order", realm.order())); + assertThat(stats, hasEntry("size", "small")); + assertThat(stats, hasEntry("ssl", false)); + assertThat(stats, hasEntry("user_search", userSearch)); + } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapUserSearchSessionFactoryTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapUserSearchSessionFactoryTests.java index 6a6f4e1fcf8..2e72c4d0c1d 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapUserSearchSessionFactoryTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapUserSearchSessionFactoryTests.java @@ -59,6 +59,7 @@ import static org.hamcrest.Matchers.nullValue; LdapUserSearchSessionFactoryTests.BackgroundConnectThreadLeakFilter.class }) public class LdapUserSearchSessionFactoryTests extends LdapTestCase { + private ClientSSLService clientSSLService; private Settings globalSettings; diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/OpenLdapTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/OpenLdapTests.java index 13c2507f95a..b09a856da10 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/OpenLdapTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/OpenLdapTests.java @@ -13,6 +13,7 @@ import org.elasticsearch.shield.authc.ldap.support.LdapSearchScope; import org.elasticsearch.shield.authc.ldap.support.LdapSession; import org.elasticsearch.shield.authc.ldap.support.LdapTestCase; import org.elasticsearch.shield.authc.ldap.support.SessionFactory; +import org.elasticsearch.shield.authc.support.DnRoleMapper; import org.elasticsearch.shield.authc.support.SecuredStringTests; import org.elasticsearch.shield.ssl.ClientSSLService; import org.elasticsearch.shield.ssl.SSLConfiguration.Global; @@ -22,9 +23,14 @@ import org.junit.Before; import java.io.IOException; import java.nio.file.Path; +import java.util.Map; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.mock; @Network public class OpenLdapTests extends ESTestCase { @@ -91,6 +97,36 @@ public class OpenLdapTests extends ESTestCase { } } + public void testUsageStats() throws Exception { + String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; + Settings.Builder settings = Settings.builder() + .put(buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, LdapSearchScope.ONE_LEVEL)) + .put("group_search.filter", "(&(objectclass=posixGroup)(memberUID={0}))") + .put("group_search.user_attribute", "uid"); + + boolean userSearch = randomBoolean(); + if (userSearch) { + settings.put("user_search.base_dn", ""); + } + + String loadBalanceType = randomFrom("failover", "round_robin"); + settings.put("load_balance.type", loadBalanceType); + + RealmConfig config = new RealmConfig("oldap-test", settings.build(), globalSettings); + LdapSessionFactory sessionFactory = new LdapSessionFactory(config, clientSSLService).init(); + LdapRealm realm = new LdapRealm(config, sessionFactory, mock(DnRoleMapper.class)); + + Map stats = realm.usageStats(); + assertThat(stats, is(notNullValue())); + assertThat(stats, hasEntry("size", "small")); + assertThat(stats, hasEntry("ssl", true)); + assertThat(stats, hasEntry("user_search", userSearch)); + assertThat(stats, hasEntry("load_balance_type", loadBalanceType)); + } + + + public void testCustomFilter() throws Exception { String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com"; diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LDAPServersTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LDAPServersTests.java index 3010b4a7559..6d34835a2c5 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LDAPServersTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LDAPServersTests.java @@ -12,6 +12,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; public class LDAPServersTests extends ESTestCase { + public void testConfigure1ldaps() { String[] urls = new String[] { "ldaps://example.com:636" }; diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancingTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancingTests.java index 7f67c006237..af2fdc58274 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancingTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/support/LdapLoadBalancingTests.java @@ -26,7 +26,7 @@ public class LdapLoadBalancingTests extends ESTestCase { LdapLoadBalancing.serverSet(null, null, settings, null, null); fail("using type [" + badType + "] should have thrown an exception"); } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), containsString("unknown server set type")); + assertThat(e.getMessage(), containsString("unknown load balance type")); } } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealmTests.java index 3fb39db2386..e976369a8a2 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealmTests.java @@ -7,9 +7,9 @@ package org.elasticsearch.shield.authc.support; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; -import org.elasticsearch.shield.user.User; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.RealmConfig; +import org.elasticsearch.shield.user.User; import org.elasticsearch.test.ESTestCase; import org.junit.Before; @@ -25,6 +25,7 @@ import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; public class CachingUsernamePasswordRealmTests extends ESTestCase { + private Settings globalSettings; @Before diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java new file mode 100644 index 00000000000..f2dc36def2b --- /dev/null +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.shield.authc.support; + +import org.elasticsearch.test.ESTestCase; + +import java.util.Locale; + +import static org.hamcrest.core.Is.is; + +/** + * + */ +public class UsernamePasswordRealmTests extends ESTestCase { + + public void testUserbaseScaelResolve() throws Exception { + int count = randomIntBetween(0, 1000); + UsernamePasswordRealm.UserbaseScale scale = UsernamePasswordRealm.UserbaseScale.resolve(count); + if (count < 10) { + assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.SMALL)); + } else if (count < 50) { + assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.MEDIUM)); + } else if (count < 250) { + assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.LARGE)); + } else { + assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.XLARGE)); + } + } + + public void testUserbaseScaleToString() throws Exception { + UsernamePasswordRealm.UserbaseScale scale = randomFrom(UsernamePasswordRealm.UserbaseScale.values()); + String value = scale.toString(); + if (scale == UsernamePasswordRealm.UserbaseScale.XLARGE) { + assertThat(value , is("x-large")); + } else { + assertThat(value , is(scale.name().toLowerCase(Locale.ROOT))); + } + } +} diff --git a/elasticsearch/x-pack/shield/src/test/resources/org/elasticsearch/transport/actions b/elasticsearch/x-pack/shield/src/test/resources/org/elasticsearch/transport/actions index 12e13193733..8ae28064a75 100644 --- a/elasticsearch/x-pack/shield/src/test/resources/org/elasticsearch/transport/actions +++ b/elasticsearch/x-pack/shield/src/test/resources/org/elasticsearch/transport/actions @@ -75,6 +75,7 @@ cluster:admin/script/delete cluster:admin/script/put indices:data/write/update cluster:monitor/xpack/info +cluster:monitor/xpack/usage cluster:monitor/xpack/license/get cluster:admin/xpack/license/delete cluster:admin/xpack/license/put diff --git a/elasticsearch/x-pack/src/test/resources/rest-api-spec/api/xpack.usage.json b/elasticsearch/x-pack/src/test/resources/rest-api-spec/api/xpack.usage.json new file mode 100644 index 00000000000..35e24a0c5f2 --- /dev/null +++ b/elasticsearch/x-pack/src/test/resources/rest-api-spec/api/xpack.usage.json @@ -0,0 +1,14 @@ +{ + "xpack.info": { + "documentation": "Retrieve information about xpack features usage", + "methods": [ "GET" ], + "url": { + "path": "/_xpack/usage", + "paths": [ "/_xpack/usage" ], + "parts": {}, + "params": { + } + }, + "body": null + } +} diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/xcontent/XContentSource.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/xcontent/XContentSource.java index bcd69abf85c..63c35b26d5d 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/xcontent/XContentSource.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/xcontent/XContentSource.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; + /** * Encapsulates the xcontent source */ @@ -48,6 +50,10 @@ public class XContentSource implements ToXContent { this(builder.bytes(), builder.contentType()); } + public XContentSource(ToXContent content) throws IOException { + this(content.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS)); + } + /** * @return The bytes reference of the source */ diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java new file mode 100644 index 00000000000..1e90de702b4 --- /dev/null +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.watcher; + +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.test.ESTestCase; +import org.junit.Before; + +import static org.hamcrest.core.Is.is; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * + */ +public class WatcherFeatureSetTests extends ESTestCase { + + private WatcherLicensee licensee; + private NamedWriteableRegistry namedWriteableRegistry; + + @Before + public void init() throws Exception { + licensee = mock(WatcherLicensee.class); + namedWriteableRegistry = mock(NamedWriteableRegistry.class); + } + + public void testWritableRegistration() throws Exception { + new WatcherFeatureSet(Settings.EMPTY, licensee, namedWriteableRegistry); + verify(namedWriteableRegistry).register(eq(WatcherFeatureSet.Usage.class), eq("xpack.usage.watcher"), anyObject()); + } + + public void testAvailable() throws Exception { + WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licensee, namedWriteableRegistry); + boolean available = randomBoolean(); + when(licensee.available()).thenReturn(available); + assertThat(featureSet.available(), is(available)); + } + + public void testEnabled() throws Exception { + boolean enabled = randomBoolean(); + Settings.Builder settings = Settings.builder(); + if (enabled) { + if (randomBoolean()) { + settings.put("xpack.watcher.enabled", enabled); + } + } else { + settings.put("xpack.watcher.enabled", enabled); + } + WatcherFeatureSet featureSet = new WatcherFeatureSet(settings.build(), licensee, namedWriteableRegistry); + assertThat(featureSet.enabled(), is(enabled)); + } + +} From 27db7c40b1c6ce40b67e971d9bc253c67842c610 Mon Sep 17 00:00:00 2001 From: uboness Date: Thu, 19 May 2016 09:19:15 +0100 Subject: [PATCH 15/16] addressed review comments Original commit: elastic/x-pack-elasticsearch@01552f5e821e3d514237ba4d21b73b245767a28f --- .../elasticsearch/graph/GraphFeatureSet.java | 21 +--- .../marvel/MonitoringFeatureSet.java | 110 +++--------------- .../marvel/MonitoringFeatureSetTests.java | 92 +++++++++++++-- .../shield/SecurityFeatureSet.java | 25 ++-- .../shield/authc/file/FileRealm.java | 2 +- .../support/CachingUsernamePasswordRealm.java | 2 +- .../authc/support/UsernamePasswordRealm.java | 12 +- .../shield/SecurityFeatureSetTests.java | 31 +++-- .../ActiveDirectoryRealmUsageTests.java | 2 +- .../authc/esnative/ReservedRealmTests.java | 2 +- .../shield/authc/file/FileRealmTests.java | 2 +- .../shield/authc/ldap/LdapRealmTests.java | 2 +- .../support/UsernamePasswordRealmTests.java | 24 ++-- .../elasticsearch/xpack/XPackFeatureSet.java | 24 +++- .../xpack/watcher/WatcherFeatureSet.java | 20 +--- .../xpack/watcher/WatcherFeatureSetTests.java | 2 +- 16 files changed, 174 insertions(+), 199 deletions(-) diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java index b83db912369..008a6942e11 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/GraphFeatureSet.java @@ -10,7 +10,6 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.XPackFeatureSet; import java.io.IOException; @@ -27,7 +26,7 @@ public class GraphFeatureSet implements XPackFeatureSet { public GraphFeatureSet(Settings settings, @Nullable GraphLicensee licensee, NamedWriteableRegistry namedWriteableRegistry) { this.enabled = Graph.enabled(settings); this.licensee = licensee; - namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); + namedWriteableRegistry.register(Usage.class, Usage.writeableName(Graph.NAME), Usage::new); } @Override @@ -51,14 +50,12 @@ public class GraphFeatureSet implements XPackFeatureSet { } @Override - public Usage usage() { + public XPackFeatureSet.Usage usage() { return new Usage(available(), enabled()); } static class Usage extends XPackFeatureSet.Usage { - static final String WRITEABLE_NAME = writeableName(Graph.NAME); - public Usage(StreamInput input) throws IOException { super(input); } @@ -66,19 +63,5 @@ public class GraphFeatureSet implements XPackFeatureSet { public Usage(boolean available, boolean enabled) { super(Graph.NAME, available, enabled); } - - @Override - public String getWriteableName() { - return WRITEABLE_NAME; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return builder.startObject() - .field(Field.AVAILABLE, available) - .field(Field.ENABLED, enabled) - .endObject(); - - } } } diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java index 7d528bb9f12..c28118df0dd 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/MonitoringFeatureSet.java @@ -10,17 +10,15 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.marvel.agent.exporter.Exporter; import org.elasticsearch.marvel.agent.exporter.Exporters; -import org.elasticsearch.marvel.agent.exporter.http.HttpExporter; -import org.elasticsearch.marvel.agent.exporter.local.LocalExporter; import org.elasticsearch.xpack.XPackFeatureSet; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; /** * @@ -29,7 +27,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet { private final boolean enabled; private final MonitoringLicensee licensee; - private final org.elasticsearch.marvel.agent.exporter.Exporters exporters; + private final Exporters exporters; @Inject public MonitoringFeatureSet(Settings settings, @Nullable MonitoringLicensee licensee, @Nullable Exporters exporters, @@ -37,7 +35,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet { this.enabled = MonitoringSettings.ENABLED.get(settings); this.licensee = licensee; this.exporters = exporters; - namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); + namedWriteableRegistry.register(Usage.class, Usage.writeableName(Monitoring.NAME), Usage::new); } @Override @@ -61,123 +59,53 @@ public class MonitoringFeatureSet implements XPackFeatureSet { } @Override - public Usage usage() { + public XPackFeatureSet.Usage usage() { return new Usage(available(), enabled(), exportersUsage(exporters)); } - static Usage.Exporters exportersUsage(Exporters exporters) { + static Map exportersUsage(Exporters exporters) { if (exporters == null) { return null; } - int local = 0; - int http = 0; - int unknown = 0; + Map usage = new HashMap<>(); for (Exporter exporter : exporters) { if (exporter.config().enabled()) { - switch (exporter.type()) { - case LocalExporter.TYPE: - local++; - break; - case HttpExporter.TYPE: - http++; - break; - default: - unknown++; - } + String type = exporter.type(); + int count = (Integer) usage.getOrDefault(type, 0); + usage.put(type, count + 1); } } - return new Usage.Exporters(local, http, unknown); + return usage; } static class Usage extends XPackFeatureSet.Usage { - private static String WRITEABLE_NAME = writeableName(Monitoring.NAME); + private static final String ENABLED_EXPORTERS_XFIELD = "enabled_exporters"; - private @Nullable - Exporters exporters; + private @Nullable Map exporters; public Usage(StreamInput in) throws IOException { super(in); - exporters = new Exporters(in); + exporters = in.readMap(); } - public Usage(boolean available, boolean enabled, Exporters exporters) { + public Usage(boolean available, boolean enabled, Map exporters) { super(Monitoring.NAME, available, enabled); this.exporters = exporters; } - @Override - public boolean available() { - return available; - } - - @Override - public boolean enabled() { - return enabled; - } - - @Override - public String getWriteableName() { - return WRITEABLE_NAME; - } - @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); - out.writeOptionalWriteable(exporters); + out.writeMap(exporters); } @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(Field.AVAILABLE, available); - builder.field(Field.ENABLED, enabled); + protected void innerXContent(XContentBuilder builder, Params params) throws IOException { + super.innerXContent(builder, params); if (exporters != null) { - builder.field(Field.ENABLED_EXPORTERS, exporters); + builder.field(ENABLED_EXPORTERS_XFIELD, exporters); } - return builder.endObject(); - } - - static class Exporters implements Writeable, ToXContent { - - private final int enabledLocalExporters; - private final int enabledHttpExporters; - private final int enabledUnknownExporters; - - public Exporters(StreamInput in) throws IOException { - this(in.readVInt(), in.readVInt(), in.readVInt()); - } - - public Exporters(int enabledLocalExporters, int enabledHttpExporters, int enabledUnknownExporters) { - this.enabledLocalExporters = enabledLocalExporters; - this.enabledHttpExporters = enabledHttpExporters; - this.enabledUnknownExporters = enabledUnknownExporters; - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeVInt(enabledLocalExporters); - out.writeVInt(enabledHttpExporters); - out.writeVInt(enabledUnknownExporters); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(Field.LOCAL, enabledLocalExporters); - builder.field(Field.HTTP, enabledHttpExporters); - if (enabledUnknownExporters > 0) { - builder.field(Field.UNKNOWN, enabledUnknownExporters); - } - return builder.endObject(); - } - } - - interface Field extends XPackFeatureSet.Usage.Field { - String ENABLED_EXPORTERS = "enabled_exporters"; - String LOCAL = "_local"; - String HTTP = "http"; - String UNKNOWN = "_unknown"; } } diff --git a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java index 84f37f47fd2..108527eb584 100644 --- a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java +++ b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/MonitoringFeatureSetTests.java @@ -7,10 +7,20 @@ package org.elasticsearch.marvel; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.marvel.agent.exporter.Exporter; import org.elasticsearch.marvel.agent.exporter.Exporters; +import org.elasticsearch.marvel.agent.exporter.http.HttpExporter; +import org.elasticsearch.marvel.agent.exporter.local.LocalExporter; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.XPackFeatureSet; +import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; import org.junit.Before; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.core.Is.is; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.eq; @@ -42,21 +52,85 @@ public class MonitoringFeatureSetTests extends ESTestCase { public void testAvailable() throws Exception { MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licensee, exporters, namedWriteableRegistry); boolean available = randomBoolean(); - when(licensee.available()).thenReturn(available); + when(licensee.isAvailable()).thenReturn(available); assertThat(featureSet.available(), is(available)); } - public void testEnabled() throws Exception { + public void testEnabledSetting() throws Exception { boolean enabled = randomBoolean(); Settings.Builder settings = Settings.builder(); - if (enabled) { - if (randomBoolean()) { - settings.put("xpack.monitoring.enabled", enabled); - } - } else { - settings.put("xpack.monitoring.enabled", enabled); - } + settings.put("xpack.monitoring.enabled", enabled); MonitoringFeatureSet featureSet = new MonitoringFeatureSet(settings.build(), licensee, exporters, namedWriteableRegistry); assertThat(featureSet.enabled(), is(enabled)); } + + public void testEnabledDefault() throws Exception { + MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licensee, exporters, namedWriteableRegistry); + assertThat(featureSet.enabled(), is(true)); + } + + public void testUsage() throws Exception { + + List exporterList = new ArrayList<>(); + int localCount = randomIntBetween(0, 5); + for (int i = 0; i < localCount; i++) { + Exporter exporter = mockExporter(LocalExporter.TYPE, true); + exporterList.add(exporter); + if (randomBoolean()) { + exporter = mockExporter(LocalExporter.TYPE, false); + exporterList.add(exporter); + } + } + int httpCount = randomIntBetween(0, 5); + for (int i = 0; i < httpCount; i++) { + Exporter exporter = mockExporter(HttpExporter.TYPE, true); + exporterList.add(exporter); + if (randomBoolean()) { + exporter = mockExporter(HttpExporter.TYPE, false); + exporterList.add(exporter); + } + } + int xCount = randomIntBetween(0, 5); + String xType = randomAsciiOfLength(10); + for (int i = 0; i < xCount; i++) { + Exporter exporter = mockExporter(xType, true); + exporterList.add(exporter); + if (randomBoolean()) { + exporter = mockExporter(xType, false); + exporterList.add(exporter); + } + } + when(exporters.iterator()).thenReturn(exporterList.iterator()); + + MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licensee, exporters, namedWriteableRegistry); + XPackFeatureSet.Usage usage = featureSet.usage(); + assertThat(usage.name(), is(featureSet.name())); + assertThat(usage.enabled(), is(featureSet.enabled())); + XContentSource source = new XContentSource(usage); + assertThat(source.getValue("enabled_exporters"), is(notNullValue())); + if (localCount > 0) { + assertThat(source.getValue("enabled_exporters.local"), is(localCount)); + } else { + assertThat(source.getValue("enabled_exporters.local"), is(nullValue())); + } + if (httpCount > 0) { + assertThat(source.getValue("enabled_exporters.http"), is(httpCount)); + } else { + assertThat(source.getValue("enabled_exporters.http"), is(nullValue())); + } + if (xCount > 0) { + assertThat(source.getValue("enabled_exporters." + xType), is(xCount)); + } else { + assertThat(source.getValue("enabled_exporters." + xType), is(nullValue())); + } + } + + private Exporter mockExporter(String type, boolean enabled) { + Exporter exporter = mock(Exporter.class); + when(exporter.type()).thenReturn(type); + Exporter.Config enabledConfig = mock(Exporter.Config.class); + when(enabledConfig.enabled()).thenReturn(enabled); + when(exporter.config()).thenReturn(enabledConfig); + return exporter; + } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java index 07eb6c86cf0..d721531659e 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/SecurityFeatureSet.java @@ -40,7 +40,7 @@ public class SecurityFeatureSet implements XPackFeatureSet { this.enabled = Security.enabled(settings); this.licenseState = licenseState; this.realms = realms; - namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); + namedWriteableRegistry.register(Usage.class, Usage.writeableName(Security.NAME), Usage::new); } @Override @@ -64,7 +64,7 @@ public class SecurityFeatureSet implements XPackFeatureSet { } @Override - public Usage usage() { + public XPackFeatureSet.Usage usage() { List> enabledRealms = buildEnabledRealms(realms); return new Usage(available(), enabled(), enabledRealms); } @@ -86,7 +86,8 @@ public class SecurityFeatureSet implements XPackFeatureSet { static class Usage extends XPackFeatureSet.Usage { - private static final String WRITEABLE_NAME = writeableName(Security.NAME); + private static final String ENABLED_REALMS_XFIELD = "enabled_realms"; + private List> enabledRealms; public Usage(StreamInput in) throws IOException { @@ -99,11 +100,6 @@ public class SecurityFeatureSet implements XPackFeatureSet { this.enabledRealms = enabledRealms; } - @Override - public String getWriteableName() { - return WRITEABLE_NAME; - } - @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); @@ -111,18 +107,11 @@ public class SecurityFeatureSet implements XPackFeatureSet { } @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - builder.field(Field.AVAILABLE, available); - builder.field(Field.ENABLED, enabled); + protected void innerXContent(XContentBuilder builder, Params params) throws IOException { + super.innerXContent(builder, params); if (enabled) { - builder.field(Field.ENABLED_REALMS, enabledRealms); + builder.field(ENABLED_REALMS_XFIELD, enabledRealms); } - return builder.endObject(); - } - - interface Field extends XPackFeatureSet.Usage.Field { - String ENABLED_REALMS = "enabled_realms"; } } } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java index 473cc11bffc..3a17b6ec243 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/file/FileRealm.java @@ -61,7 +61,7 @@ public class FileRealm extends CachingUsernamePasswordRealm { public Map usageStats() { Map stats = super.usageStats(); // here we can determine the size based on the in mem user store - stats.put("size", UserbaseScale.resolve(userPasswdStore.usersCount())); + stats.put("size", UserbaseSize.resolve(userPasswdStore.usersCount())); return stats; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java index a977be5f7e1..c95616e9f94 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/CachingUsernamePasswordRealm.java @@ -168,7 +168,7 @@ public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm @Override public Map usageStats() { Map stats = super.usageStats(); - stats.put("size", UserbaseScale.resolve(cache.count()).toString()); + stats.put("size", UserbaseSize.resolve(cache.count()).toString()); return stats; } diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java index 1b7138f7845..57886b923d6 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealm.java @@ -39,21 +39,25 @@ public abstract class UsernamePasswordRealm extends Realm } } - public enum UserbaseScale { + public enum UserbaseSize { + TINY, SMALL, MEDIUM, LARGE, XLARGE; - public static UserbaseScale resolve(int count) { + public static UserbaseSize resolve(int count) { if (count < 10) { + return TINY; + } + if (count < 100) { return SMALL; } - if (count < 50) { + if (count < 500) { return MEDIUM; } - if (count < 250) { + if (count < 1000) { return LARGE; } return XLARGE; diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java index f07afb60f88..be1a6412f2e 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/SecurityFeatureSetTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.Realms; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.XPackFeatureSet; import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; import org.junit.Before; @@ -55,20 +56,20 @@ public class SecurityFeatureSetTests extends ESTestCase { assertThat(featureSet.available(), is(available)); } - public void testEnabled() throws Exception { + public void testEnabledSetting() throws Exception { boolean enabled = randomBoolean(); - Settings.Builder settings = Settings.builder(); - if (enabled) { - if (randomBoolean()) { - settings.put("xpack.security.enabled", enabled); - } - } else { - settings.put("xpack.security.enabled", enabled); - } - SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState, realms, namedWriteableRegistry); + Settings settings = Settings.builder() + .put("xpack.security.enabled", enabled) + .build(); + SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, namedWriteableRegistry); assertThat(featureSet.enabled(), is(enabled)); } + public void testEnabledDefault() throws Exception { + SecurityFeatureSet featureSet = new SecurityFeatureSet(Settings.EMPTY, licenseState, realms, namedWriteableRegistry); + assertThat(featureSet.enabled(), is(true)); + } + public void testUsage() throws Exception { boolean available = randomBoolean(); @@ -77,13 +78,7 @@ public class SecurityFeatureSetTests extends ESTestCase { Settings.Builder settings = Settings.builder(); boolean enabled = randomBoolean(); - if (enabled) { - if (randomBoolean()) { - settings.put("xpack.security.enabled", enabled); - } - } else { - settings.put("xpack.security.enabled", enabled); - } + settings.put("xpack.security.enabled", enabled); List realmsList= new ArrayList<>(); @@ -100,7 +95,7 @@ public class SecurityFeatureSetTests extends ESTestCase { when(realms.iterator()).thenReturn(realmsList.iterator()); SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState, realms, namedWriteableRegistry); - SecurityFeatureSet.Usage usage = featureSet.usage(); + XPackFeatureSet.Usage usage = featureSet.usage(); assertThat(usage, is(notNullValue())); assertThat(usage.name(), is(Security.NAME)); assertThat(usage.enabled(), is(enabled)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java index 2eeb5ad9dd6..ed71448bad5 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/activedirectory/ActiveDirectoryRealmUsageTests.java @@ -37,7 +37,7 @@ public class ActiveDirectoryRealmUsageTests extends AbstractActiveDirectoryInteg assertThat(stats, hasEntry("type", "active_directory")); assertThat(stats, hasEntry("name", "ad-test")); assertThat(stats, hasEntry("order", realm.order())); - assertThat(stats, hasEntry("size", "small")); + assertThat(stats, hasEntry("size", "tiny")); assertThat(stats, hasEntry("ssl", true)); assertThat(stats, hasEntry("load_balance_type", loadBalanceType)); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ReservedRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ReservedRealmTests.java index 7a7f5500731..80fb786688a 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ReservedRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/esnative/ReservedRealmTests.java @@ -120,7 +120,7 @@ public class ReservedRealmTests extends ESTestCase { } public void testHelperMethods() { - final User expectedUser = randomFrom((User) XPackUser.INSTANCE, (User) KibanaUser.INSTANCE); + final User expectedUser = randomFrom((User) XPackUser.INSTANCE, KibanaUser.INSTANCE); final String principal = expectedUser.principal(); assertThat(ReservedRealm.isReserved(principal), is(true)); assertThat(ReservedRealm.getUser(principal), sameInstance(expectedUser)); diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java index e1c42bc5775..29a953199a3 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/file/FileRealmTests.java @@ -180,7 +180,7 @@ public class FileRealmTests extends ESTestCase { assertThat(usage, hasEntry("type", "file")); assertThat(usage, hasEntry("name", "file-realm")); assertThat(usage, hasEntry("order", order)); - assertThat(usage, hasEntry("size", UsernamePasswordRealm.UserbaseScale.resolve(userCount))); + assertThat(usage, hasEntry("size", UsernamePasswordRealm.UserbaseSize.resolve(userCount))); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java index 409ae31c7d0..7ab06210a42 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTests.java @@ -250,7 +250,7 @@ public class LdapRealmTests extends LdapTestCase { assertThat(stats, hasEntry("type", "ldap")); assertThat(stats, hasEntry("name", "ldap-realm")); assertThat(stats, hasEntry("order", realm.order())); - assertThat(stats, hasEntry("size", "small")); + assertThat(stats, hasEntry("size", "tiny")); assertThat(stats, hasEntry("ssl", false)); assertThat(stats, hasEntry("user_search", userSearch)); } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java index f2dc36def2b..8549a18f220 100644 --- a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/authc/support/UsernamePasswordRealmTests.java @@ -18,25 +18,27 @@ public class UsernamePasswordRealmTests extends ESTestCase { public void testUserbaseScaelResolve() throws Exception { int count = randomIntBetween(0, 1000); - UsernamePasswordRealm.UserbaseScale scale = UsernamePasswordRealm.UserbaseScale.resolve(count); + UsernamePasswordRealm.UserbaseSize size = UsernamePasswordRealm.UserbaseSize.resolve(count); if (count < 10) { - assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.SMALL)); - } else if (count < 50) { - assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.MEDIUM)); - } else if (count < 250) { - assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.LARGE)); + assertThat(size, is(UsernamePasswordRealm.UserbaseSize.SMALL)); + } else if (count < 100) { + assertThat(size, is(UsernamePasswordRealm.UserbaseSize.SMALL)); + } else if (count < 500) { + assertThat(size, is(UsernamePasswordRealm.UserbaseSize.MEDIUM)); + } else if (count < 1000) { + assertThat(size, is(UsernamePasswordRealm.UserbaseSize.LARGE)); } else { - assertThat(scale, is(UsernamePasswordRealm.UserbaseScale.XLARGE)); + assertThat(size, is(UsernamePasswordRealm.UserbaseSize.XLARGE)); } } public void testUserbaseScaleToString() throws Exception { - UsernamePasswordRealm.UserbaseScale scale = randomFrom(UsernamePasswordRealm.UserbaseScale.values()); - String value = scale.toString(); - if (scale == UsernamePasswordRealm.UserbaseScale.XLARGE) { + UsernamePasswordRealm.UserbaseSize size = randomFrom(UsernamePasswordRealm.UserbaseSize.values()); + String value = size.toString(); + if (size == UsernamePasswordRealm.UserbaseSize.XLARGE) { assertThat(value , is("x-large")); } else { - assertThat(value , is(scale.name().toLowerCase(Locale.ROOT))); + assertThat(value , is(size.name().toLowerCase(Locale.ROOT))); } } } diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java index ef0717c985d..ccbe45d984f 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackFeatureSet.java @@ -9,6 +9,7 @@ import org.elasticsearch.common.io.stream.NamedWriteable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; import java.io.IOException; @@ -29,6 +30,9 @@ public interface XPackFeatureSet { abstract class Usage implements ToXContent, NamedWriteable { + private static final String AVAILABLE_XFIELD = "available"; + private static final String ENABLED_XFIELD = "enabled"; + protected final String name; protected final boolean available; protected final boolean enabled; @@ -55,18 +59,30 @@ public interface XPackFeatureSet { return enabled; } + @Override + public String getWriteableName() { + return writeableName(name); + } + @Override public void writeTo(StreamOutput out) throws IOException { out.writeBoolean(available); out.writeBoolean(enabled); } - protected interface Field { - String AVAILABLE = "available"; - String ENABLED = "enabled"; + @Override + public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + innerXContent(builder, params); + return builder.endObject(); } - protected static String writeableName(String featureName) { + protected void innerXContent(XContentBuilder builder, Params params) throws IOException { + builder.field(AVAILABLE_XFIELD, available); + builder.field(ENABLED_XFIELD, enabled); + } + + public static String writeableName(String featureName) { return "xpack.usage." + featureName; } } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java index d57f918469b..dd97c2f6e47 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/WatcherFeatureSet.java @@ -10,7 +10,6 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.xpack.XPackFeatureSet; import java.io.IOException; @@ -27,7 +26,7 @@ public class WatcherFeatureSet implements XPackFeatureSet { public WatcherFeatureSet(Settings settings, @Nullable WatcherLicensee licensee, NamedWriteableRegistry namedWriteableRegistry) { this.enabled = Watcher.enabled(settings); this.licensee = licensee; - namedWriteableRegistry.register(Usage.class, Usage.WRITEABLE_NAME, Usage::new); + namedWriteableRegistry.register(Usage.class, Usage.writeableName(Watcher.NAME), Usage::new); } @Override @@ -51,14 +50,12 @@ public class WatcherFeatureSet implements XPackFeatureSet { } @Override - public Usage usage() { + public XPackFeatureSet.Usage usage() { return new Usage(available(), enabled()); } static class Usage extends XPackFeatureSet.Usage { - private static final String WRITEABLE_NAME = writeableName(Watcher.NAME); - public Usage(StreamInput input) throws IOException { super(input); } @@ -67,18 +64,5 @@ public class WatcherFeatureSet implements XPackFeatureSet { super(Watcher.NAME, available, enabled); } - @Override - public String getWriteableName() { - return WRITEABLE_NAME; - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return builder.startObject() - .field(Field.AVAILABLE, available) - .field(Field.ENABLED, enabled) - .endObject(); - - } } } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java index 1e90de702b4..3eb671a08aa 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherFeatureSetTests.java @@ -39,7 +39,7 @@ public class WatcherFeatureSetTests extends ESTestCase { public void testAvailable() throws Exception { WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licensee, namedWriteableRegistry); boolean available = randomBoolean(); - when(licensee.available()).thenReturn(available); + when(licensee.isAvailable()).thenReturn(available); assertThat(featureSet.available(), is(available)); } From 5d93b51472018bfc804d383ed1c401958b38e9f8 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Fri, 20 May 2016 15:23:11 -0600 Subject: [PATCH 16/16] Fix compilation for ScriptMode removal See: https://github.com/elastic/elasticsearch/pull/18502 Original commit: elastic/x-pack-elasticsearch@b0422d13dfe8c929aa2d91b2b54551bd4164e0d5 --- .../org/elasticsearch/script/MockMustacheScriptEngine.java | 4 +--- .../test/java/org/elasticsearch/script/SleepScriptEngine.java | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/MockMustacheScriptEngine.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/MockMustacheScriptEngine.java index bd9cb51019d..6430fde4a16 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/MockMustacheScriptEngine.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/MockMustacheScriptEngine.java @@ -5,7 +5,6 @@ */ package org.elasticsearch.script; -import org.elasticsearch.script.ScriptMode; import org.elasticsearch.xpack.common.text.DefaultTextTemplateEngine; import java.util.Collections; @@ -29,8 +28,7 @@ public class MockMustacheScriptEngine extends MockScriptEngine { } public void onModule(ScriptModule module) { - module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(MockMustacheScriptEngine.class, - NAME, ScriptMode.ON)); + module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(MockMustacheScriptEngine.class, NAME, true)); } } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/SleepScriptEngine.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/SleepScriptEngine.java index fe34b142ad3..c0cf787d7e8 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/SleepScriptEngine.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/script/SleepScriptEngine.java @@ -7,7 +7,6 @@ package org.elasticsearch.script; import org.elasticsearch.common.Nullable; import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.script.ScriptMode; import org.elasticsearch.search.lookup.SearchLookup; import java.io.IOException; @@ -39,7 +38,7 @@ public class SleepScriptEngine implements ScriptEngineService { public void onModule(ScriptModule module) { module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(SleepScriptEngine.class, - SleepScriptEngine.NAME, ScriptMode.ON)); + SleepScriptEngine.NAME, true)); } }