Disable licensing services and management APIs for tribe node

closes elastic/elasticsearch#1426

Original commit: elastic/x-pack-elasticsearch@d8a312b1b5
This commit is contained in:
Areek Zillur 2016-04-19 10:18:17 -04:00
parent dcccb02595
commit d9e9f7dfd0
3 changed files with 294 additions and 36 deletions

View File

@ -6,8 +6,6 @@
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.action.ActionModule; import org.elasticsearch.action.ActionModule;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.component.LifecycleComponent; import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
@ -28,15 +26,19 @@ import org.elasticsearch.license.plugin.rest.RestDeleteLicenseAction;
import org.elasticsearch.license.plugin.rest.RestGetLicenseAction; import org.elasticsearch.license.plugin.rest.RestGetLicenseAction;
import org.elasticsearch.license.plugin.rest.RestPutLicenseAction; import org.elasticsearch.license.plugin.rest.RestPutLicenseAction;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import static org.elasticsearch.xpack.XPackPlugin.isTribeClientNode;
import static org.elasticsearch.xpack.XPackPlugin.isTribeNode;
import static org.elasticsearch.xpack.XPackPlugin.transportClientMode;
public class Licensing { public class Licensing {
public static final String NAME = "license"; public static final String NAME = "license";
private final boolean isEnabled; private final boolean isTransportClient;
protected final boolean transportClient; private final boolean isTribeNode;
static { static {
MetaData.registerPrototype(LicensesMetaData.TYPE, LicensesMetaData.PROTO); MetaData.registerPrototype(LicensesMetaData.TYPE, LicensesMetaData.PROTO);
@ -44,12 +46,12 @@ public class Licensing {
@Inject @Inject
public Licensing(Settings settings) { public Licensing(Settings settings) {
this.transportClient = TransportClient.CLIENT_TYPE.equals(settings.get(Client.CLIENT_TYPE_SETTING_S.getKey())); isTransportClient = transportClientMode(settings);
isEnabled = transportClient == false; isTribeNode = isTribeNode(settings);
} }
public void onModule(NetworkModule module) { public void onModule(NetworkModule module) {
if (transportClient == false) { if (isTransportClient == false && isTribeNode == false) {
module.registerRestHandler(RestPutLicenseAction.class); module.registerRestHandler(RestPutLicenseAction.class);
module.registerRestHandler(RestGetLicenseAction.class); module.registerRestHandler(RestGetLicenseAction.class);
module.registerRestHandler(RestDeleteLicenseAction.class); module.registerRestHandler(RestDeleteLicenseAction.class);
@ -57,21 +59,22 @@ public class Licensing {
} }
public void onModule(ActionModule module) { public void onModule(ActionModule module) {
module.registerAction(PutLicenseAction.INSTANCE, TransportPutLicenseAction.class); if (isTribeNode == false) {
module.registerAction(GetLicenseAction.INSTANCE, TransportGetLicenseAction.class); module.registerAction(PutLicenseAction.INSTANCE, TransportPutLicenseAction.class);
module.registerAction(DeleteLicenseAction.INSTANCE, TransportDeleteLicenseAction.class); module.registerAction(GetLicenseAction.INSTANCE, TransportGetLicenseAction.class);
module.registerAction(DeleteLicenseAction.INSTANCE, TransportDeleteLicenseAction.class);
}
} }
public Collection<Class<? extends LifecycleComponent>> nodeServices() { public Collection<Class<? extends LifecycleComponent>> nodeServices() {
Collection<Class<? extends LifecycleComponent>> services = new ArrayList<>(); if (isTransportClient == false && isTribeNode == false) {
if (isEnabled) { return Collections.<Class<? extends LifecycleComponent>>singletonList(LicensesService.class);
services.add(LicensesService.class);
} }
return services; return Collections.emptyList();
} }
public Collection<Module> nodeModules() { public Collection<Module> nodeModules() {
if (isEnabled) { if (isTransportClient == false && isTribeNode == false) {
return Collections.<Module>singletonList(new LicensingModule()); return Collections.<Module>singletonList(new LicensingModule());
} }
return Collections.emptyList(); return Collections.emptyList();

View File

@ -0,0 +1,234 @@
/*
* 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.action.Action;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.discovery.zen.ping.unicast.UnicastZenPing;
import org.elasticsearch.graph.Graph;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseRequest;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.license.plugin.action.get.GetLicenseRequest;
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
import org.elasticsearch.marvel.Monitoring;
import org.elasticsearch.node.Node;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.Security;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.NodeConfigurationSource;
import org.elasticsearch.test.TestCluster;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.Watcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
@ClusterScope(scope = Scope.TEST, transportClientRatio = 0, numClientNodes = 0, numDataNodes = 0)
public class LicenseTribeTests extends ESIntegTestCase {
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(XPackPlugin.featureEnabledSetting(Security.NAME), false)
.put(XPackPlugin.featureEnabledSetting(Monitoring.NAME), false)
.put(XPackPlugin.featureEnabledSetting(Watcher.NAME), false)
.put(XPackPlugin.featureEnabledSetting(Graph.NAME), false)
.put(NetworkModule.HTTP_ENABLED.getKey(), false)
.put(Node.NODE_LOCAL_SETTING.getKey(), true)
.build();
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.<Class<? extends Plugin>>singletonList(XPackPlugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
public void testTribeSetup() throws Exception {
NodeConfigurationSource nodeConfigurationSource = new NodeConfigurationSource() {
@Override
public Settings nodeSettings(int nodeOrdinal) {
return LicenseTribeTests.this.nodeSettings(nodeOrdinal);
}
@Override
public Collection<Class<? extends Plugin>> nodePlugins() {
return LicenseTribeTests.this.nodePlugins();
}
@Override
public Settings transportClientSettings() {
return LicenseTribeTests.this.transportClientSettings();
}
@Override
public Collection<Class<? extends Plugin>> transportClientPlugins() {
return LicenseTribeTests.this.transportClientPlugins();
}
};
final InternalTestCluster cluster2 = new InternalTestCluster(InternalTestCluster.configuredNodeMode(),
randomLong(), createTempDir(), 2, 2,
UUIDs.randomBase64UUID(random()), nodeConfigurationSource, 0, false, "tribe_node2",
getMockPlugins(), getClientWrapper());
cluster2.beforeTest(random(), 0.0);
cluster2.ensureAtLeastNumDataNodes(2);
logger.info("create 2 indices, test1 on t1, and test2 on t2");
assertAcked(internalCluster().client().admin().indices().prepareCreate("test1").get());
assertAcked(cluster2.client().admin().indices().prepareCreate("test2").get());
ensureYellow(internalCluster());
ensureYellow(cluster2);
Map<String,String> asMap = internalCluster().getDefaultSettings().getAsMap();
Settings.Builder tribe1Defaults = Settings.builder();
Settings.Builder tribe2Defaults = Settings.builder();
for (Map.Entry<String, String> entry : asMap.entrySet()) {
if (entry.getKey().startsWith("path.")) {
continue;
}
tribe1Defaults.put("tribe.t1." + entry.getKey(), entry.getValue());
tribe2Defaults.put("tribe.t2." + entry.getKey(), entry.getValue());
}
// give each tribe it's unicast hosts to connect to
tribe1Defaults.putArray("tribe.t1." + UnicastZenPing.DISCOVERY_ZEN_PING_UNICAST_HOSTS_SETTING.getKey(),
getUnicastHosts(internalCluster().client()));
tribe1Defaults.putArray("tribe.t2." + UnicastZenPing.DISCOVERY_ZEN_PING_UNICAST_HOSTS_SETTING.getKey(),
getUnicastHosts(cluster2.client()));
Settings merged = Settings.builder()
.put("tribe.t1.cluster.name", internalCluster().getClusterName())
.put("tribe.t2.cluster.name", cluster2.getClusterName())
.put("tribe.blocks.write", false)
.put(tribe1Defaults.build())
.put(tribe2Defaults.build())
.put(internalCluster().getDefaultSettings())
.put("node.name", "tribe_node") // make sure we can identify threads from this node
.put(Node.NODE_LOCAL_SETTING.getKey(), true)
.build();
final Node tribeNode = new Node(merged).start();
Client tribeClient = tribeNode.client();
logger.info("wait till tribe has the same nodes as the 2 clusters");
assertBusy(() -> {
DiscoveryNodes tribeNodes = tribeNode.client().admin().cluster().prepareState().get().getState().getNodes();
assertThat(countDataNodesForTribe("t1", tribeNodes),
equalTo(internalCluster().client().admin().cluster().prepareState().get().getState()
.getNodes().getDataNodes().size()));
assertThat(countDataNodesForTribe("t2", tribeNodes),
equalTo(cluster2.client().admin().cluster().prepareState().get().getState()
.getNodes().getDataNodes().size()));
});
verifyActionOnTribeNode(tribeClient);
verifyActionOnDataNode((randomBoolean() ? internalCluster() : cluster2).dataNodeClient());
verifyActionOnDataNode((randomBoolean() ? internalCluster() : cluster2).masterClient());
try {
cluster2.wipe(Collections.<String>emptySet());
} catch (NoNodeAvailableException ignored) {
} finally {
cluster2.afterTest();
}
tribeNode.close();
cluster2.close();
}
protected void verifyActionOnDataNode(Client dataNodeClient) throws Exception {
dataNodeClient.execute(GetLicenseAction.INSTANCE, new GetLicenseRequest()).get();
dataNodeClient.execute(PutLicenseAction.INSTANCE, new PutLicenseRequest()
.license(generateSignedLicense(TimeValue.timeValueHours(1))));
dataNodeClient.execute(DeleteLicenseAction.INSTANCE, new DeleteLicenseRequest());
}
protected void verifyActionOnTribeNode(Client tribeClient) {
failAction(tribeClient, GetLicenseAction.INSTANCE);
failAction(tribeClient, PutLicenseAction.INSTANCE);
failAction(tribeClient, DeleteLicenseAction.INSTANCE);
}
protected void failAction(Client client, Action action) {
try {
client.execute(action, action.newRequestBuilder(client).request());
fail("expected [" + action.name() + "] to fail");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), containsString("failed to find action"));
}
}
private void ensureYellow(TestCluster testCluster) {
ClusterHealthResponse actionGet;
while (true) {
try {
actionGet = testCluster.client().admin().cluster()
.health(Requests.clusterHealthRequest().waitForYellowStatus()
.waitForEvents(Priority.LANGUID).waitForRelocatingShards(0)).actionGet();
break;
} catch (NoNodeAvailableException ignored) {
}
}
if (actionGet.isTimedOut()) {
logger.info("ensureGreen timed out, cluster state:\n{}\n{}", testCluster.client().admin().cluster()
.prepareState().get().getState().prettyPrint(),
testCluster.client().admin().cluster().preparePendingClusterTasks().get().prettyPrint());
assertThat("timed out waiting for yellow state", actionGet.isTimedOut(), equalTo(false));
}
assertThat(actionGet.getStatus(), anyOf(equalTo(ClusterHealthStatus.YELLOW), equalTo(ClusterHealthStatus.GREEN)));
}
private int countDataNodesForTribe(String tribeName, DiscoveryNodes nodes) {
int count = 0;
for (DiscoveryNode node : nodes) {
if (!node.isDataNode()) {
continue;
}
if (tribeName.equals(node.getAttributes().get("tribe.name"))) {
count++;
}
}
return count;
}
public static String[] getUnicastHosts(Client client) {
ArrayList<String> unicastHosts = new ArrayList<>();
NodesInfoResponse nodeInfos = client.admin().cluster().prepareNodesInfo().clear().setTransport(true).get();
for (NodeInfo info : nodeInfos.getNodes()) {
TransportAddress address = info.getTransport().getAddress().publishAddress();
unicastHosts.add(address.getAddress() + ":" + address.getPort());
}
return unicastHosts.toArray(new String[unicastHosts.size()]);
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.License; import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction; import org.elasticsearch.license.plugin.action.delete.DeleteLicenseAction;
@ -18,20 +19,42 @@ import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
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.license.plugin.core.LicensesStatus; import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.marvel.Monitoring;
import org.junit.After; import org.elasticsearch.node.Node;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.Security;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.Watcher;
import java.util.Collection;
import java.util.Collections;
import static org.elasticsearch.license.plugin.TestUtils.dateMath; import static org.elasticsearch.license.plugin.TestUtils.dateMath;
import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense; import static org.elasticsearch.license.plugin.TestUtils.generateSignedLicense;
import static org.elasticsearch.test.ESIntegTestCase.Scope.TEST;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.not;
@ClusterScope(scope = TEST, numDataNodes = 10) public class LicensesTransportTests extends ESSingleNodeTestCase {
public class LicensesTransportTests extends AbstractLicensesIntegrationTestCase {
@After @Override
public void beforeTest() throws Exception { protected boolean resetNodeAfterTest() {
wipeAllLicenses(); return true;
}
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Collections.singletonList(XPackPlugin.class);
}
@Override
protected Settings nodeSettings() {
Settings.Builder newSettings = Settings.builder();
newSettings.put(XPackPlugin.featureEnabledSetting(Security.NAME), false);
newSettings.put(XPackPlugin.featureEnabledSetting(Monitoring.NAME), false);
newSettings.put(XPackPlugin.featureEnabledSetting(Watcher.NAME), false);
newSettings.put(Node.NODE_DATA_SETTING.getKey(), true);
return newSettings.build();
} }
public void testEmptyGetLicense() throws Exception { public void testEmptyGetLicense() throws Exception {
@ -47,7 +70,8 @@ public class LicensesTransportTests extends AbstractLicensesIntegrationTestCase
// put license // put license
PutLicenseRequestBuilder putLicenseRequestBuilder = PutLicenseRequestBuilder putLicenseRequestBuilder =
new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(signedLicense); new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(signedLicense)
.setAcknowledge(true);
PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
@ -63,7 +87,8 @@ public class LicensesTransportTests extends AbstractLicensesIntegrationTestCase
// put license source // put license source
PutLicenseRequestBuilder putLicenseRequestBuilder = PutLicenseRequestBuilder putLicenseRequestBuilder =
new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(licenseString); new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(licenseString)
.setAcknowledge(true);
PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
@ -97,25 +122,20 @@ public class LicensesTransportTests extends AbstractLicensesIntegrationTestCase
public void testPutExpiredLicense() throws Exception { public void testPutExpiredLicense() throws Exception {
License expiredLicense = generateSignedLicense(dateMath("now-10d/d", System.currentTimeMillis()), TimeValue.timeValueMinutes(2)); License expiredLicense = generateSignedLicense(dateMath("now-10d/d", System.currentTimeMillis()), TimeValue.timeValueMinutes(2));
License signedLicense = generateSignedLicense(TimeValue.timeValueMinutes(2));
PutLicenseRequestBuilder builder = new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE); PutLicenseRequestBuilder builder = new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE);
builder.setLicense(signedLicense);
// put license should return valid (as there is one valid license)
PutLicenseResponse putLicenseResponse = builder.get();
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
builder.setLicense(expiredLicense); builder.setLicense(expiredLicense);
putLicenseResponse = builder.get(); PutLicenseResponse putLicenseResponse = builder.get();
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.EXPIRED)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.EXPIRED));
// get license should not return the expired license // get license should not return the expired license
GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster(), GetLicenseAction.INSTANCE).get(); GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster(), GetLicenseAction.INSTANCE).get();
assertThat(getLicenseResponse.license(), equalTo(signedLicense)); assertThat(getLicenseResponse.license(), not(expiredLicense));
} }
public void testPutLicensesSimple() throws Exception { public void testPutLicensesSimple() throws Exception {
License basicSignedLicense = generateSignedLicense("basic", TimeValue.timeValueMinutes(5)); License basicSignedLicense = generateSignedLicense("basic", TimeValue.timeValueMinutes(5));
PutLicenseRequestBuilder putLicenseRequestBuilder = PutLicenseRequestBuilder putLicenseRequestBuilder =
new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(basicSignedLicense); new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(basicSignedLicense)
.setAcknowledge(true);
PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get();
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster(), GetLicenseAction.INSTANCE).get(); GetLicenseResponse getLicenseResponse = new GetLicenseRequestBuilder(client().admin().cluster(), GetLicenseAction.INSTANCE).get();
@ -133,7 +153,8 @@ public class LicensesTransportTests extends AbstractLicensesIntegrationTestCase
public void testRemoveLicensesSimple() throws Exception { public void testRemoveLicensesSimple() throws Exception {
License goldLicense = generateSignedLicense("gold", TimeValue.timeValueMinutes(5)); License goldLicense = generateSignedLicense("gold", TimeValue.timeValueMinutes(5));
PutLicenseRequestBuilder putLicenseRequestBuilder = PutLicenseRequestBuilder putLicenseRequestBuilder =
new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(goldLicense); new PutLicenseRequestBuilder(client().admin().cluster(), PutLicenseAction.INSTANCE).setLicense(goldLicense)
.setAcknowledge(true);
PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get(); PutLicenseResponse putLicenseResponse = putLicenseRequestBuilder.get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true)); assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID)); assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));