Fix license metadata serialization
Original commit: elastic/x-pack-elasticsearch@4c838f18d4
This commit is contained in:
parent
8d6e0fc164
commit
783970f0e7
|
@ -147,17 +147,24 @@ public class LicensesMetaData implements MetaData.Custom {
|
||||||
}
|
}
|
||||||
if (fieldName != null) {
|
if (fieldName != null) {
|
||||||
if (fieldName.equals(Fields.LICENSES)) {
|
if (fieldName.equals(Fields.LICENSES)) {
|
||||||
|
if (parser.nextToken() == XContentParser.Token.START_ARRAY) {
|
||||||
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||||
|
if (parser.currentToken().isValue()) {
|
||||||
signatures.add(parser.text());
|
signatures.add(parser.text());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fieldName.equals(Fields.TRIAL_LICENSES)) {
|
}
|
||||||
|
} else if (fieldName.equals(Fields.TRIAL_LICENSES)) {
|
||||||
|
if (parser.nextToken() == XContentParser.Token.START_ARRAY) {
|
||||||
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
|
||||||
|
if (parser.currentToken().isValue()) {
|
||||||
encodedTrialLicenses.add(parser.text());
|
encodedTrialLicenses.add(parser.text());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return new LicensesMetaData(signatures, encodedTrialLicenses);
|
return new LicensesMetaData(signatures, encodedTrialLicenses);
|
||||||
}
|
}
|
||||||
|
@ -167,10 +174,8 @@ public class LicensesMetaData implements MetaData.Custom {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void toXContent(LicensesMetaData licensesMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
|
public void toXContent(LicensesMetaData licensesMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
builder.startObject();
|
|
||||||
builder.array(Fields.LICENSES, licensesMetaData.signatures.toArray(new String[licensesMetaData.signatures.size()]));
|
builder.array(Fields.LICENSES, licensesMetaData.signatures.toArray(new String[licensesMetaData.signatures.size()]));
|
||||||
builder.array(Fields.TRIAL_LICENSES, licensesMetaData.encodedTrialLicenses.toArray(new String [licensesMetaData.encodedTrialLicenses.size()]));
|
builder.array(Fields.TRIAL_LICENSES, licensesMetaData.encodedTrialLicenses.toArray(new String [licensesMetaData.encodedTrialLicenses.size()]));
|
||||||
builder.endObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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.license.plugin;
|
||||||
|
|
||||||
|
import org.elasticsearch.cluster.ClusterService;
|
||||||
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
import org.elasticsearch.cluster.ProcessedClusterStateUpdateTask;
|
||||||
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.license.plugin.core.LicensesMetaData;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public abstract class AbstractLicensesIntegrationTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
return ImmutableSettings.settingsBuilder()
|
||||||
|
.put("plugins.load_classpath_plugins", false)
|
||||||
|
.put("plugin.types", LicensePlugin.class.getName())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings transportClientSettings() {
|
||||||
|
// Plugin should be loaded on the transport client as well
|
||||||
|
return nodeSettings(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void wipeAllLicenses() throws InterruptedException {
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
ClusterService clusterService = internalCluster().getInstance(ClusterService.class, internalCluster().getMasterName());
|
||||||
|
clusterService.submitStateUpdateTask("delete licensing metadata", new ProcessedClusterStateUpdateTask() {
|
||||||
|
@Override
|
||||||
|
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClusterState execute(ClusterState currentState) throws Exception {
|
||||||
|
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
||||||
|
mdBuilder.putCustom(LicensesMetaData.TYPE, null);
|
||||||
|
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(String source, @Nullable Throwable t) {
|
||||||
|
logger.error("error on metaData cleanup after test", t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
latch.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,25 +36,11 @@ import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
|
|
||||||
@ClusterScope(scope = SUITE, numDataNodes = 10)
|
@ClusterScope(scope = SUITE, numDataNodes = 10)
|
||||||
public class LicenseTransportTests extends ElasticsearchIntegrationTest {
|
public class LicenseTransportTests extends AbstractLicensesIntegrationTests {
|
||||||
|
|
||||||
private static String pubKeyPath = null;
|
private static String pubKeyPath = null;
|
||||||
private static String priKeyPath = null;
|
private static String priKeyPath = null;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
|
||||||
return ImmutableSettings.settingsBuilder()
|
|
||||||
.put("plugins.load_classpath_plugins", false)
|
|
||||||
.put("plugin.types", LicensePlugin.class.getName())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings transportClientSettings() {
|
|
||||||
// Plugin should be loaded on the transport client as well
|
|
||||||
return nodeSettings(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup() throws IOException, URISyntaxException {
|
public static void setup() throws IOException, URISyntaxException {
|
||||||
priKeyPath = Paths.get(LicenseTransportTests.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
priKeyPath = Paths.get(LicenseTransportTests.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
||||||
|
|
|
@ -5,61 +5,39 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.license.plugin;
|
package org.elasticsearch.license.plugin;
|
||||||
|
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
|
|
||||||
import org.elasticsearch.common.base.Predicate;
|
import org.elasticsearch.common.base.Predicate;
|
||||||
import org.elasticsearch.common.collect.Lists;
|
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.license.AbstractLicensingTestBase;
|
|
||||||
import org.elasticsearch.license.core.ESLicense;
|
import org.elasticsearch.license.core.ESLicense;
|
||||||
import org.elasticsearch.license.licensor.ESLicenseSigner;
|
import org.elasticsearch.license.licensor.ESLicenseSigner;
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
|
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
|
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
|
|
||||||
import org.elasticsearch.license.plugin.core.LicensesManagerService;
|
import org.elasticsearch.license.plugin.core.LicensesManagerService;
|
||||||
import org.elasticsearch.license.plugin.core.LicensesService;
|
|
||||||
import org.elasticsearch.license.plugin.core.LicensesStatus;
|
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
|
||||||
import org.elasticsearch.test.InternalTestCluster;
|
import org.elasticsearch.test.InternalTestCluster;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPriKeyPath;
|
import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPriKeyPath;
|
||||||
import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPubKeyPath;
|
import static org.elasticsearch.license.AbstractLicensingTestBase.getTestPubKeyPath;
|
||||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
|
|
||||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
|
||||||
@ClusterScope(scope = TEST, numDataNodes = 3, numClientNodes = 0)
|
@ClusterScope(scope = TEST, numDataNodes = 3, numClientNodes = 0)
|
||||||
public class LicensesPluginIntegrationTests extends ElasticsearchIntegrationTest {
|
public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationTests {
|
||||||
|
|
||||||
private final int trialLicenseDurationInSeconds = 5;
|
private final int trialLicenseDurationInSeconds = 5;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
return ImmutableSettings.settingsBuilder()
|
return ImmutableSettings.settingsBuilder()
|
||||||
.put("plugins.load_classpath_plugins", false)
|
.put(super.nodeSettings(nodeOrdinal))
|
||||||
.put("test_consumer_plugin.trial_license_duration_in_seconds", trialLicenseDurationInSeconds)
|
.put("test_consumer_plugin.trial_license_duration_in_seconds", trialLicenseDurationInSeconds)
|
||||||
.put("plugin.types", LicensePlugin.class.getName() + "," + TestConsumerPlugin.class.getName())
|
.put("plugin.types", LicensePlugin.class.getName() + "," + TestConsumerPlugin.class.getName())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings transportClientSettings() {
|
|
||||||
// Plugin should be loaded on the transport client as well
|
|
||||||
return nodeSettings(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
// managerService should report feature to be enabled on all data nodes
|
// managerService should report feature to be enabled on all data nodes
|
||||||
|
|
|
@ -18,8 +18,6 @@ import org.elasticsearch.license.plugin.action.get.GetLicenseRequestBuilder;
|
||||||
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
|
import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
|
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
|
||||||
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
|
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -32,34 +30,42 @@ import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
|
||||||
@ClusterScope(scope = SUITE, numDataNodes = 0)
|
@ClusterScope(scope = SUITE, numDataNodes = 0)
|
||||||
public class LicensesServiceClusterRestartTest extends ElasticsearchIntegrationTest {
|
public class LicensesServiceClusterRestartTest extends AbstractLicensesIntegrationTests {
|
||||||
|
|
||||||
static String priKeyPath;
|
static String priKeyPath;
|
||||||
static String pubKeyPath;
|
static String pubKeyPath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Settings transportClientSettings() {
|
protected Settings transportClientSettings() {
|
||||||
// Plugin should be loaded on the transport client as well
|
return super.transportClientSettings();
|
||||||
return settingsBuilder().build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
return ImmutableSettings.settingsBuilder()
|
||||||
|
.put(super.nodeSettings(nodeOrdinal))
|
||||||
|
.put("gateway.type", "local")
|
||||||
|
.put("format", "json")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
@Test @Ignore
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
priKeyPath = Paths.get(LicensesServiceClusterRestartTest.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
priKeyPath = Paths.get(LicensesServiceClusterRestartTest.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
||||||
pubKeyPath = Paths.get(LicensesServiceClusterRestartTest.class.getResource("/public.key").toURI()).toAbsolutePath().toString();
|
pubKeyPath = Paths.get(LicensesServiceClusterRestartTest.class.getResource("/public.key").toURI()).toAbsolutePath().toString();
|
||||||
|
|
||||||
logger.info("--> starting 1 nodes");
|
logger.info("--> starting 1 nodes");
|
||||||
String node1 = internalCluster().startNode(settingsBuilder());
|
String node1 = internalCluster().startNode();
|
||||||
|
|
||||||
ensureGreen();
|
ensureGreen();
|
||||||
|
wipeAllLicenses();
|
||||||
|
|
||||||
final List<ESLicense> esLicenses = putLicense(node1);
|
final List<ESLicense> esLicenses = putLicense(node1);
|
||||||
final Client startNodeClient = internalCluster().startNodeClient(settingsBuilder().build());
|
final Client startNodeClient = internalCluster().startNodeClient(settingsBuilder().build());
|
||||||
//TODO: just pass node name instead
|
//TODO: just pass node name instead
|
||||||
getAndCheckLicense(startNodeClient, esLicenses);
|
getAndCheckLicense(startNodeClient, esLicenses);
|
||||||
|
|
||||||
logger.info("--> cluster state before full cluster restart");
|
logger.info("--> cluster state before full cluster restart");
|
||||||
ClusterState clusterState = client().admin().cluster().prepareState().get().getState();
|
ClusterState clusterState = clusterService().state();
|
||||||
logger.info("Cluster state: {}", clusterState);
|
logger.info("Cluster state: {}", clusterState);
|
||||||
|
|
||||||
logger.info("--> restart all nodes");
|
logger.info("--> restart all nodes");
|
||||||
|
|
|
@ -21,29 +21,18 @@ import static org.hamcrest.Matchers.equalTo;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@ElasticsearchIntegrationTest.ClusterScope(scope = TEST, numDataNodes = 10, numClientNodes = 0)
|
@ElasticsearchIntegrationTest.ClusterScope(scope = TEST, numDataNodes = 10, numClientNodes = 0)
|
||||||
public class LicensesServiceNodeTests extends ElasticsearchIntegrationTest {
|
public class LicensesServiceNodeTests extends AbstractLicensesIntegrationTests {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
return nodeSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Settings nodeSettings() {
|
|
||||||
return ImmutableSettings.settingsBuilder()
|
return ImmutableSettings.settingsBuilder()
|
||||||
.put("plugins.load_classpath_plugins", false)
|
.put(super.nodeSettings(nodeOrdinal))
|
||||||
.put("test_consumer_plugin.trial_license_duration_in_seconds", 10)
|
.put("test_consumer_plugin.trial_license_duration_in_seconds", 10)
|
||||||
.putArray("plugin.types", LicensePlugin.class.getName(), TestConsumerPlugin.class.getName())
|
.putArray("plugin.types", LicensePlugin.class.getName(), TestConsumerPlugin.class.getName())
|
||||||
.put(InternalNode.HTTP_ENABLED, true)
|
.put(InternalNode.HTTP_ENABLED, true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings transportClientSettings() {
|
|
||||||
// Plugin should be loaded on the transport client as well
|
|
||||||
return nodeSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestLogging("_root:DEBUG")
|
@TestLogging("_root:DEBUG")
|
||||||
public void testPluginStatus() throws Exception {
|
public void testPluginStatus() throws Exception {
|
||||||
|
|
|
@ -42,57 +42,22 @@ import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
@ClusterScope(scope = TEST, numDataNodes = 10)
|
@ClusterScope(scope = TEST, numDataNodes = 10)
|
||||||
public class LicensesServiceTests extends ElasticsearchIntegrationTest {
|
public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
|
||||||
|
|
||||||
|
|
||||||
private static String pubKeyPath = null;
|
private static String pubKeyPath = null;
|
||||||
private static String priKeyPath = null;
|
private static String priKeyPath = null;
|
||||||
private static String node = null;
|
private static String node = null;
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
|
||||||
return ImmutableSettings.settingsBuilder()
|
|
||||||
.put("plugins.load_classpath_plugins", false)
|
|
||||||
.put("plugin.types", LicensePlugin.class.getName())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Settings transportClientSettings() {
|
|
||||||
// Plugin should be loaded on the transport client as well
|
|
||||||
return nodeSettings(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup() throws IOException, URISyntaxException {
|
public static void setup() throws IOException, URISyntaxException {
|
||||||
priKeyPath = Paths.get(LicenseTransportTests.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
priKeyPath = Paths.get(LicenseTransportTests.class.getResource("/private.key").toURI()).toAbsolutePath().toString();
|
||||||
pubKeyPath = Paths.get(LicenseTransportTests.class.getResource("/public.key").toURI()).toAbsolutePath().toString();
|
pubKeyPath = Paths.get(LicenseTransportTests.class.getResource("/public.key").toURI()).toAbsolutePath().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeTest() throws Exception {
|
public void beforeTest() throws Exception {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
wipeAllLicenses();
|
||||||
// todo: fix with awaitBusy
|
|
||||||
masterClusterService().submitStateUpdateTask("delete licensing metadata", new ProcessedClusterStateUpdateTask() {
|
|
||||||
@Override
|
|
||||||
public void clusterStateProcessed(String source, ClusterState oldState, ClusterState newState) {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClusterState execute(ClusterState currentState) throws Exception {
|
|
||||||
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
|
|
||||||
mdBuilder.putCustom(LicensesMetaData.TYPE, null);
|
|
||||||
return ClusterState.builder(currentState).metaData(mdBuilder).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(String source, @Nullable Throwable t) {
|
|
||||||
logger.error("error on metaData cleanup after test", t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
latch.await();
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
DiscoveryNodes discoveryNodes = LicensesServiceTests.masterClusterService().state().getNodes();
|
DiscoveryNodes discoveryNodes = LicensesServiceTests.masterClusterService().state().getNodes();
|
||||||
|
|
Loading…
Reference in New Issue