|
@@ -21,11 +21,11 @@ import org.elasticsearch.client.Response;
|
|
|
import org.elasticsearch.client.ResponseException;
|
|
import org.elasticsearch.client.ResponseException;
|
|
|
import org.elasticsearch.client.transport.NoNodeAvailableException;
|
|
import org.elasticsearch.client.transport.NoNodeAvailableException;
|
|
|
import org.elasticsearch.client.transport.TransportClient;
|
|
import org.elasticsearch.client.transport.TransportClient;
|
|
|
-import org.elasticsearch.cluster.routing.ShardRoutingState;
|
|
|
|
|
import org.elasticsearch.common.settings.SecureString;
|
|
import org.elasticsearch.common.settings.SecureString;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
|
|
import org.elasticsearch.discovery.DiscoveryModule;
|
|
import org.elasticsearch.discovery.DiscoveryModule;
|
|
|
|
|
+import org.elasticsearch.license.License.OperationMode;
|
|
|
import org.elasticsearch.node.MockNode;
|
|
import org.elasticsearch.node.MockNode;
|
|
|
import org.elasticsearch.node.Node;
|
|
import org.elasticsearch.node.Node;
|
|
|
import org.elasticsearch.plugins.Plugin;
|
|
import org.elasticsearch.plugins.Plugin;
|
|
@@ -54,6 +54,7 @@ import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
import java.util.Collection;
|
|
import java.util.Collection;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
|
@@ -68,7 +69,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
|
|
@TestLogging("org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE,org.elasticsearch.action.search:TRACE," +
|
|
@TestLogging("org.elasticsearch.cluster.service:TRACE,org.elasticsearch.discovery.zen:TRACE,org.elasticsearch.action.search:TRACE," +
|
|
|
"org.elasticsearch.search:TRACE")
|
|
"org.elasticsearch.search:TRACE")
|
|
|
public class LicensingTests extends SecurityIntegTestCase {
|
|
public class LicensingTests extends SecurityIntegTestCase {
|
|
|
- public static final String ROLES =
|
|
|
|
|
|
|
+ private static final String ROLES =
|
|
|
SecuritySettingsSource.TEST_ROLE + ":\n" +
|
|
SecuritySettingsSource.TEST_ROLE + ":\n" +
|
|
|
" cluster: [ all ]\n" +
|
|
" cluster: [ all ]\n" +
|
|
|
" indices:\n" +
|
|
" indices:\n" +
|
|
@@ -91,7 +92,7 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|
|
" - names: 'b'\n" +
|
|
" - names: 'b'\n" +
|
|
|
" privileges: [all]\n";
|
|
" privileges: [all]\n";
|
|
|
|
|
|
|
|
- public static final String USERS_ROLES =
|
|
|
|
|
|
|
+ private static final String USERS_ROLES =
|
|
|
SecuritySettingsSource.CONFIG_STANDARD_USER_ROLES +
|
|
SecuritySettingsSource.CONFIG_STANDARD_USER_ROLES +
|
|
|
"role_a:user_a,user_b\n" +
|
|
"role_a:user_a,user_b\n" +
|
|
|
"role_b:user_b\n";
|
|
"role_b:user_b\n";
|
|
@@ -131,8 +132,8 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Before
|
|
@Before
|
|
|
- public void resetLicensing() {
|
|
|
|
|
- enableLicensing();
|
|
|
|
|
|
|
+ public void resetLicensing() throws InterruptedException {
|
|
|
|
|
+ enableLicensing(OperationMode.BASIC);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@After
|
|
@After
|
|
@@ -155,11 +156,7 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|
|
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
|
|
assertEquals(DocWriteResponse.Result.CREATED, indexResponse.getResult());
|
|
|
|
|
|
|
|
refresh();
|
|
refresh();
|
|
|
- // wait for all replicas to be started (to make sure that there are no more cluster state updates when we disable licensing)
|
|
|
|
|
- assertBusy(() -> assertTrue(client().admin().cluster().prepareState().get().getState().routingTable()
|
|
|
|
|
- .shardsWithState(ShardRoutingState.INITIALIZING).isEmpty()));
|
|
|
|
|
-
|
|
|
|
|
- Client client = internalCluster().transportClient();
|
|
|
|
|
|
|
+ final Client client = internalCluster().transportClient();
|
|
|
|
|
|
|
|
disableLicensing();
|
|
disableLicensing();
|
|
|
|
|
|
|
@@ -273,7 +270,6 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|
|
public void testNodeJoinWithoutSecurityExplicitlyEnabled() throws Exception {
|
|
public void testNodeJoinWithoutSecurityExplicitlyEnabled() throws Exception {
|
|
|
License.OperationMode mode = randomFrom(License.OperationMode.GOLD, License.OperationMode.PLATINUM, License.OperationMode.STANDARD);
|
|
License.OperationMode mode = randomFrom(License.OperationMode.GOLD, License.OperationMode.PLATINUM, License.OperationMode.STANDARD);
|
|
|
enableLicensing(mode);
|
|
enableLicensing(mode);
|
|
|
- ensureGreen();
|
|
|
|
|
|
|
|
|
|
final List<String> seedHosts = internalCluster().masterClient().admin().cluster().nodesInfo(new NodesInfoRequest()).get()
|
|
final List<String> seedHosts = internalCluster().masterClient().admin().cluster().nodesInfo(new NodesInfoRequest()).get()
|
|
|
.getNodes().stream().map(n -> n.getTransport().getAddress().publishAddress().toString()).distinct()
|
|
.getNodes().stream().map(n -> n.getTransport().getAddress().publishAddress().toString()).distinct()
|
|
@@ -304,23 +300,64 @@ public class LicensingTests extends SecurityIntegTestCase {
|
|
|
assertThat(ee.status(), is(RestStatus.FORBIDDEN));
|
|
assertThat(ee.status(), is(RestStatus.FORBIDDEN));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static void disableLicensing() {
|
|
|
|
|
- disableLicensing(License.OperationMode.BASIC);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public static void disableLicensing(License.OperationMode operationMode) {
|
|
|
|
|
- for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
|
|
|
|
|
- licenseState.update(operationMode, false, null);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ private void disableLicensing() throws InterruptedException {
|
|
|
|
|
+ // This method first makes sure licensing is enabled everywhere so that we can execute
|
|
|
|
|
+ // monitoring actions to ensure we have a stable cluster and only then do we disable.
|
|
|
|
|
+ // This is done in an await busy since there is a chance that the enabling of the license
|
|
|
|
|
+ // is overwritten by some other cluster activity and the node throws an exception while we
|
|
|
|
|
+ // wait for things to stabilize!
|
|
|
|
|
+ final boolean success = awaitBusy(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
|
|
|
|
|
+ if (licenseState.isAuthAllowed() == false) {
|
|
|
|
|
+ enableLicensing(OperationMode.BASIC);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ensureGreen();
|
|
|
|
|
+ ensureClusterSizeConsistency();
|
|
|
|
|
+ ensureClusterStateConsistency();
|
|
|
|
|
+
|
|
|
|
|
+ // apply the disabling of the license once the cluster is stable
|
|
|
|
|
+ for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
|
|
|
|
|
+ licenseState.update(OperationMode.BASIC, false, null);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("Caught exception while disabling license", e);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }, 30L, TimeUnit.SECONDS);
|
|
|
|
|
+ assertTrue(success);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static void enableLicensing() {
|
|
|
|
|
- enableLicensing(License.OperationMode.BASIC);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- public static void enableLicensing(License.OperationMode operationMode) {
|
|
|
|
|
- for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
|
|
|
|
|
- licenseState.update(operationMode, true, null);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ private void enableLicensing(License.OperationMode operationMode) throws InterruptedException {
|
|
|
|
|
+ // do this in an await busy since there is a chance that the enabling of the license is
|
|
|
|
|
+ // overwritten by some other cluster activity and the node throws an exception while we
|
|
|
|
|
+ // wait for things to stabilize!
|
|
|
|
|
+ final boolean success = awaitBusy(() -> {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // first update the license so we can execute monitoring actions
|
|
|
|
|
+ for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
|
|
|
|
|
+ licenseState.update(operationMode, true, null);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ensureGreen();
|
|
|
|
|
+ ensureClusterSizeConsistency();
|
|
|
|
|
+ ensureClusterStateConsistency();
|
|
|
|
|
+
|
|
|
|
|
+ // re-apply the update in case any node received an updated cluster state that triggered the license state
|
|
|
|
|
+ // to change
|
|
|
|
|
+ for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
|
|
|
|
|
+ licenseState.update(operationMode, true, null);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("Caught exception while enabling license", e);
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }, 30L, TimeUnit.SECONDS);
|
|
|
|
|
+ assertTrue(success);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|