diff --git a/pom.xml b/pom.xml
index 70de30e5f29..78b89079d91 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,11 +10,18 @@
1.4.0-SNAPSHOT
+ 4.10.0
+
+ org.apache.lucene
+ lucene-test-framework
+ ${lucene.version}
+ test
+
org.elasticsearch
elasticsearch
@@ -22,13 +29,24 @@
test
test-jar
-
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+ test
+
junit
junit
4.11
test
+
+ com.carrotsearch.randomizedtesting
+ randomizedtesting-runner
+ 2.1.2
+ test
+
@@ -147,6 +165,121 @@
+
+ com.carrotsearch.randomizedtesting
+ junit4-maven-plugin
+ 2.1.2
+
+
+ tests
+ test
+
+ junit4
+
+
+ 20
+ pipe,warn
+ true
+
+
+
+
+
+
+
+
+
+
+ ${tests.jvms}
+
+
+
+
+
+
+ **/*Tests.class
+ **/*Test.class
+
+
+ **/Abstract*.class
+ **/*StressTest.class
+
+
+ -Xmx${tests.heap.size}
+ -Xms${tests.heap.size}
+ -Xss256k
+ -XX:MaxPermSize=128m
+ -XX:MaxDirectMemorySize=512m
+ -Des.logger.prefix=
+ -XX:+HeapDumpOnOutOfMemoryError
+ -XX:HeapDumpPath=${tests.heapdump.path}
+
+ ${tests.shuffle}
+ ${tests.verbose}
+ ${tests.seed}
+ ${tests.failfast}
+ false
+
+ .
+
+
+ ${tests.bwc}
+ ${tests.bwc.path}
+ ${tests.bwc.version}
+ ${tests.jvm.argline}
+ ${tests.processors}
+ ${tests.appendseed}
+ ${tests.iters}
+ ${tests.maxfailures}
+ ${tests.failfast}
+ ${tests.class}
+ ${tests.method}
+ ${tests.nightly}
+ ${tests.verbose}
+ ${tests.badapples}
+ ${tests.weekly}
+ ${tests.slow}
+ ${tests.awaitsfix}
+ ${tests.slow}
+ ${tests.timeoutSuite}
+ ${tests.showSuccess}
+ ${tests.integration}
+ ${tests.client.ratio}
+ ${tests.enable_mock_modules}
+ ${tests.assertion.disabled}
+ ${tests.rest}
+ ${tests.rest.suite}
+ ${tests.rest.blacklist}
+ ${tests.rest.spec}
+ ${tests.network}
+ ${tests.cluster}
+ ${tests.heap.size}
+ ${tests.filter}
+ ${project.version}
+ ${env.ES_TEST_LOCAL}
+ ${es.node.mode}
+ ${es.logger.level}
+ ${tests.security.manager}
+ ${tests.compatibility}
+ true
+
+ ${project.build.directory}
+ ${basedir}/dev-tools/tests.policy
+
+
+
+
+
diff --git a/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java b/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java
index 1799e8e883e..091169b4046 100644
--- a/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java
+++ b/src/main/java/org/elasticsearch/license/core/LicenseBuilders.java
@@ -50,7 +50,7 @@ public class LicenseBuilders {
}
public static class LicensesBuilder {
- private Map licenseMap;
+ private Map licenseMap = new HashMap<>();
public LicensesBuilder() {
}
@@ -60,11 +60,15 @@ public class LicenseBuilders {
}
public LicensesBuilder license(ESLicense license) {
- initLicenses();
putIfAppropriate(license);
return this;
}
+ public LicensesBuilder licenseAsIs(ESLicense license) {
+ licenseMap.put(license.feature(), license);
+ return this;
+ }
+
public LicensesBuilder licenses(Collection licenses) {
for (ESLicense esLicense : licenses) {
license(esLicense);
@@ -100,12 +104,6 @@ public class LicenseBuilders {
};
}
- private void initLicenses() {
- if (licenseMap == null) {
- licenseMap = new HashMap<>();
- }
- }
-
/**
* Add a {@link org.elasticsearch.license.core.ESLicenses.ESLicense} to
* {@link org.elasticsearch.license.core.ESLicenses} only if
diff --git a/src/main/java/org/elasticsearch/license/manager/Utils.java b/src/main/java/org/elasticsearch/license/manager/Utils.java
index d62f734e29e..2b22c6b4b6d 100644
--- a/src/main/java/org/elasticsearch/license/manager/Utils.java
+++ b/src/main/java/org/elasticsearch/license/manager/Utils.java
@@ -23,7 +23,7 @@ public class Utils {
private Utils() {
}
- static ESLicenses getESLicensesFromSignatures(final LicenseManager licenseManager, Set signatures) {
+ public static ESLicenses getESLicensesFromSignatures(final LicenseManager licenseManager, Set signatures) {
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
for (String signature : signatures) {
licensesBuilder.license(getESLicenseFromSignature(licenseManager, signature));
diff --git a/src/main/java/org/elasticsearch/license/plugin/LicensePlugin.java b/src/main/java/org/elasticsearch/license/plugin/LicensePlugin.java
index a5751220557..bc78792ab26 100644
--- a/src/main/java/org/elasticsearch/license/plugin/LicensePlugin.java
+++ b/src/main/java/org/elasticsearch/license/plugin/LicensePlugin.java
@@ -6,10 +6,12 @@
package org.elasticsearch.license.plugin;
import org.elasticsearch.action.ActionModule;
+import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
import org.elasticsearch.license.plugin.action.get.TransportGetLicenseAction;
import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
import org.elasticsearch.license.plugin.action.put.TransportPutLicenseAction;
+import org.elasticsearch.license.plugin.cluster.LicensesMetaData;
import org.elasticsearch.license.plugin.rest.RestGetLicenseAction;
import org.elasticsearch.license.plugin.rest.RestPutLicenseAction;
import org.elasticsearch.plugins.AbstractPlugin;
@@ -18,6 +20,10 @@ import org.elasticsearch.rest.RestModule;
//TODO: plugin hooks
public class LicensePlugin extends AbstractPlugin {
+ static {
+ MetaData.registerFactory(LicensesMetaData.TYPE, LicensesMetaData.FACTORY);
+ }
+
@Override
public String name() {
return "license";
@@ -38,4 +44,6 @@ public class LicensePlugin extends AbstractPlugin {
module.registerAction(PutLicenseAction.INSTANCE, TransportPutLicenseAction.class);
module.registerAction(GetLicenseAction.INSTANCE, TransportGetLicenseAction.class);
}
+
+ //TODO: module binding? (LicenseModule)
}
diff --git a/src/main/java/org/elasticsearch/license/plugin/Utils.java b/src/main/java/org/elasticsearch/license/plugin/Utils.java
new file mode 100644
index 00000000000..c9a438e3f41
--- /dev/null
+++ b/src/main/java/org/elasticsearch/license/plugin/Utils.java
@@ -0,0 +1,9 @@
+/*
+ * 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;
+
+public class Utils {
+}
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/Utils.java b/src/main/java/org/elasticsearch/license/plugin/action/Utils.java
new file mode 100644
index 00000000000..0c1d0114b74
--- /dev/null
+++ b/src/main/java/org/elasticsearch/license/plugin/action/Utils.java
@@ -0,0 +1,86 @@
+/*
+ * 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.action;
+
+import org.elasticsearch.common.collect.ImmutableMap;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.license.core.ESLicenses;
+import org.elasticsearch.license.core.LicenseBuilders;
+
+import java.io.IOException;
+import java.util.Map;
+
+import static org.elasticsearch.license.core.ESLicenses.*;
+
+public class Utils {
+
+
+ public static ESLicenses readLicensesFrom(StreamInput in) throws IOException {
+ final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
+ boolean exists = in.readBoolean();
+ if (exists) {
+ int size = in.readVInt();
+ for (int i = 0; i < size; i++) {
+ licensesBuilder.licenseAsIs(licenseFromMap(in.readMap()));
+ }
+ }
+ return licensesBuilder.build();
+ }
+
+ public static void writeLicensesTo(ESLicenses esLicenses, StreamOutput out) throws IOException {
+ if (esLicenses == null) {
+ out.writeBoolean(false);
+ return;
+ }
+ out.writeBoolean(true);
+ out.writeVInt(esLicenses.licenses().size());
+ for (ESLicense esLicense : esLicenses) {
+ out.writeMap(licenseAsMap(esLicense));
+ }
+ }
+
+ public static Map licenseAsMap(ESLicense esLicense) {
+ ImmutableMap.Builder builder = ImmutableMap.builder();
+ builder.put(LicenseFields.UID, esLicense.uid());
+ builder.put(LicenseFields.TYPE, esLicense.type());
+ builder.put(LicenseFields.SUBSCRIPTION_TYPE, esLicense.subscriptionType());
+ builder.put(LicenseFields.ISSUE_DATE, esLicense.issueDate());
+ builder.put(LicenseFields.FEATURE, esLicense.feature());
+ builder.put(LicenseFields.EXPIRY_DATE, esLicense.expiryDate());
+ builder.put(LicenseFields.MAX_NODES, esLicense.maxNodes());
+ builder.put(LicenseFields.ISSUED_TO, esLicense.issuedTo());
+ builder.put(LicenseFields.SIGNATURE, esLicense.signature());
+ return builder.build();
+ }
+
+ public static ESLicense licenseFromMap(Map map) {
+ return LicenseBuilders.licenseBuilder(false)
+ .uid((String) map.get(LicenseFields.UID))
+ .type((Type) map.get(LicenseFields.TYPE))
+ .subscriptionType((SubscriptionType) map.get(LicenseFields.SUBSCRIPTION_TYPE))
+ .issueDate((Long) map.get(LicenseFields.ISSUE_DATE))
+ .feature((FeatureType) map.get(LicenseFields.FEATURE))
+ .expiryDate((Long) map.get(LicenseFields.EXPIRY_DATE))
+ .maxNodes((Integer) map.get(LicenseFields.MAX_NODES))
+ .issuedTo((String) map.get(LicenseFields.ISSUED_TO))
+ .signature((String) map.get(LicenseFields.SIGNATURE))
+ .build();
+
+ }
+
+ final static class LicenseFields {
+ private final static String UID = "uid";
+ private final static String TYPE = "type";
+ private final static String SUBSCRIPTION_TYPE = "subscription_type";
+ private final static String ISSUE_DATE = "issue_date";
+ private final static String FEATURE = "feature";
+ private final static String EXPIRY_DATE = "expiry_date";
+ private final static String MAX_NODES = "max_nodes";
+ private final static String ISSUED_TO = "issued_to";
+ private final static String SIGNATURE = "signature";
+ }
+}
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequest.java b/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequest.java
index e73524b0a67..86674843d7a 100644
--- a/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequest.java
+++ b/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequest.java
@@ -16,19 +16,12 @@ import java.io.IOException;
public class GetLicenseRequest extends MasterNodeReadOperationRequest {
- GetLicenseRequest() {
+ public GetLicenseRequest() {
}
-
@Override
public ActionRequestValidationException validate() {
return null;
- /*ActionRequestValidationException validationException = null;
- if (repositories == null) {
- validationException = addValidationError("repositories is null", validationException);
- }
- return validationException;
- */
}
@Override
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequestBuilder.java b/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequestBuilder.java
index e095eb672b5..dd5a022a7b9 100644
--- a/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequestBuilder.java
+++ b/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseRequestBuilder.java
@@ -12,7 +12,7 @@ import org.elasticsearch.client.ClusterAdminClient;
public class GetLicenseRequestBuilder extends MasterNodeReadOperationRequestBuilder {
/**
- * Creates new get repository request builder
+ * Creates new get licenses request builder
*
* @param clusterAdminClient cluster admin client
*/
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseResponse.java b/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseResponse.java
index 1e9bf979efa..49ad1e0175c 100644
--- a/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseResponse.java
+++ b/src/main/java/org/elasticsearch/license/plugin/action/get/GetLicenseResponse.java
@@ -6,71 +6,42 @@
package org.elasticsearch.license.plugin.action.get;
import org.elasticsearch.action.ActionResponse;
-import org.elasticsearch.cluster.metadata.RepositoryMetaData;
-import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.license.core.ESLicenses;
+import org.elasticsearch.license.plugin.cluster.LicensesMetaData;
import java.io.IOException;
-import java.util.Iterator;
-public class GetLicenseResponse extends ActionResponse implements Iterable {
+import static org.elasticsearch.license.plugin.action.Utils.readLicensesFrom;
+import static org.elasticsearch.license.plugin.action.Utils.writeLicensesTo;
- //TODO: use LicenseMetaData instead
- private ImmutableList repositories = ImmutableList.of();
+public class GetLicenseResponse extends ActionResponse {
+ private ESLicenses licenses = null;
GetLicenseResponse() {
}
- GetLicenseResponse(ImmutableList repositories) {
- this.repositories = repositories;
+ GetLicenseResponse(ESLicenses esLicenses) {
+ this.licenses = esLicenses;
}
- /**
- * List of repositories to return
- *
- * @return list or repositories
- */
- public ImmutableList repositories() {
- return repositories;
+ public ESLicenses licenses() {
+ return licenses;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
- int size = in.readVInt();
- ImmutableList.Builder repositoryListBuilder = ImmutableList.builder();
- for (int j = 0; j < size; j++) {
- repositoryListBuilder.add(new RepositoryMetaData(
- in.readString(),
- in.readString(),
- ImmutableSettings.readSettingsFromStream(in))
- );
- }
- repositories = repositoryListBuilder.build();
+ licenses = readLicensesFrom(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
- out.writeVInt(repositories.size());
- for (RepositoryMetaData repository : repositories) {
- out.writeString(repository.name());
- out.writeString(repository.type());
- ImmutableSettings.writeSettingsToStream(repository.settings(), out);
- }
+ writeLicensesTo(licenses, out);
}
- /**
- * Iterator over the repositories data
- *
- * @return iterator over the repositories data
- */
- @Override
- public Iterator iterator() {
- return repositories.iterator();
- }
}
\ No newline at end of file
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/get/TransportGetLicenseAction.java b/src/main/java/org/elasticsearch/license/plugin/action/get/TransportGetLicenseAction.java
index 0e74335a5fc..7f6836ffc27 100644
--- a/src/main/java/org/elasticsearch/license/plugin/action/get/TransportGetLicenseAction.java
+++ b/src/main/java/org/elasticsearch/license/plugin/action/get/TransportGetLicenseAction.java
@@ -18,6 +18,7 @@ import org.elasticsearch.cluster.metadata.RepositoriesMetaData;
import org.elasticsearch.cluster.metadata.RepositoryMetaData;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.license.plugin.cluster.LicensesMetaData;
import org.elasticsearch.repositories.RepositoryMissingException;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
@@ -52,31 +53,8 @@ public class TransportGetLicenseAction extends TransportMasterNodeReadOperationA
@Override
protected void masterOperation(final GetLicenseRequest request, ClusterState state, final ActionListener listener) throws ElasticsearchException {
- //TODO: impl after custom metadata impl
- /*
MetaData metaData = state.metaData();
- RepositoriesMetaData repositories = metaData.custom(RepositoriesMetaData.TYPE);
- if (request.repositories().length == 0 || (request.repositories().length == 1 && "_all".equals(request.repositories()[0]))) {
- if (repositories != null) {
- listener.onResponse(new GetRepositoriesResponse(repositories.repositories()));
- } else {
- listener.onResponse(new GetRepositoriesResponse(ImmutableList.of()));
- }
- } else {
- if (repositories != null) {
- ImmutableList.Builder repositoryListBuilder = ImmutableList.builder();
- for (String repository : request.repositories()) {
- RepositoryMetaData repositoryMetaData = repositories.repository(repository);
- if (repositoryMetaData == null) {
- listener.onFailure(new RepositoryMissingException(repository));
- return;
- }
- repositoryListBuilder.add(repositoryMetaData);
- }
- listener.onResponse(new GetRepositoriesResponse(repositoryListBuilder.build()));
- } else {
- listener.onFailure(new RepositoryMissingException(request.repositories()[0]));
- }
- }*/
+ LicensesMetaData licenses = metaData.custom(LicensesMetaData.TYPE);
+ listener.onResponse(new GetLicenseResponse(licenses));
}
}
\ No newline at end of file
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/put/PutLicenseRequest.java b/src/main/java/org/elasticsearch/license/plugin/action/put/PutLicenseRequest.java
index c627965a4f8..6c3af1f20ba 100644
--- a/src/main/java/org/elasticsearch/license/plugin/action/put/PutLicenseRequest.java
+++ b/src/main/java/org/elasticsearch/license/plugin/action/put/PutLicenseRequest.java
@@ -15,6 +15,9 @@ import org.elasticsearch.license.core.LicenseUtils;
import java.io.IOException;
+import static org.elasticsearch.license.plugin.action.Utils.readLicensesFrom;
+import static org.elasticsearch.license.plugin.action.Utils.writeLicensesTo;
+
public class PutLicenseRequest extends AcknowledgedRequest {
private ESLicenses license;
@@ -61,14 +64,14 @@ public class PutLicenseRequest extends AcknowledgedRequest {
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
- license = LicenseUtils.readLicenseFromInputStream(in);
+ license = readLicensesFrom(in);
readTimeout(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
- LicenseUtils.dumpLicenseAsJson(license, out);
+ writeLicensesTo(license, out);
writeTimeout(out);
}
}
diff --git a/src/main/java/org/elasticsearch/license/plugin/action/put/TransportPutLicenseAction.java b/src/main/java/org/elasticsearch/license/plugin/action/put/TransportPutLicenseAction.java
index 846a34a51f9..6b0b8c1449c 100644
--- a/src/main/java/org/elasticsearch/license/plugin/action/put/TransportPutLicenseAction.java
+++ b/src/main/java/org/elasticsearch/license/plugin/action/put/TransportPutLicenseAction.java
@@ -11,21 +11,24 @@ import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
import org.elasticsearch.cluster.block.ClusterBlockException;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.license.plugin.service.LicensesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
public class TransportPutLicenseAction extends TransportMasterNodeOperationAction {
- //private final RepositoriesService repositoriesService
+ private final LicensesService licensesService;
@Inject
public TransportPutLicenseAction(Settings settings, TransportService transportService, ClusterService clusterService,
- ThreadPool threadPool, ActionFilters actionFilters) {
+ LicensesService licensesService, ThreadPool threadPool, ActionFilters actionFilters) {
super(settings, PutLicenseAction.NAME, transportService, clusterService, threadPool, actionFilters);
+ this.licensesService = licensesService;
}
@@ -52,8 +55,20 @@ public class TransportPutLicenseAction extends TransportMasterNodeOperationActio
@Override
protected void masterOperation(final PutLicenseRequest request, ClusterState state, final ActionListener listener) throws ElasticsearchException {
//TODO
+ licensesService.registerLicenses("put_licenses []",request, new ActionListener() {
+ @Override
+ public void onResponse(ClusterStateUpdateResponse clusterStateUpdateResponse) {
+ listener.onResponse(new PutLicenseResponse(clusterStateUpdateResponse.isAcknowledged()));
+ }
+
+ @Override
+ public void onFailure(Throwable e) {
+ listener.onFailure(e);
+ }
+ });
+
/*
- repositoriesService.registerRepository(new RepositoriesService.RegisterRepositoryRequest("put_repository [" + request.name() + "]", request.name(), request.type())
+ repositoriesService.registerLicenses(new RepositoriesService.RegisterRepositoryRequest("put_repository [" + request.name() + "]", request.name(), request.type())
.settings(request.settings())
.masterNodeTimeout(request.masterNodeTimeout())
.ackTimeout(request.timeout()), new ActionListener() {
diff --git a/src/main/java/org/elasticsearch/license/plugin/cluster/LicensesMetaData.java b/src/main/java/org/elasticsearch/license/plugin/cluster/LicensesMetaData.java
new file mode 100644
index 00000000000..01fd12b158c
--- /dev/null
+++ b/src/main/java/org/elasticsearch/license/plugin/cluster/LicensesMetaData.java
@@ -0,0 +1,173 @@
+/*
+ * 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.cluster;
+
+import org.elasticsearch.ElasticsearchParseException;
+import org.elasticsearch.cluster.metadata.MetaData;
+import org.elasticsearch.common.collect.ImmutableMap;
+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 org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.license.core.ESLicenses;
+
+import java.io.IOException;
+import java.util.*;
+
+import static org.elasticsearch.license.plugin.action.Utils.*;
+
+/**
+ * Contains metadata about registered snapshot licenses
+ */
+public class LicensesMetaData implements MetaData.Custom, ESLicenses {
+
+ public static final String TYPE = "licenses";
+
+ public static final Factory FACTORY = new Factory();
+
+ private final ImmutableMap licenses;
+
+ /**
+ * Constructs new repository metadata
+ *
+ * @param esLicenses list of esLicense
+ */
+ public LicensesMetaData(List esLicenses) {
+ this.licenses = map(esLicenses);
+ }
+
+ public LicensesMetaData(ESLicenses esLicenses) {
+ this.licenses = map(esLicenses);
+ }
+
+ private static ImmutableMap map(Iterable esLicenses) {
+ final ImmutableMap.Builder builder = ImmutableMap.builder();
+ for (ESLicense esLicense : esLicenses) {
+ builder.put(esLicense.feature(), esLicense);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns list of currently registered licenses
+ *
+ * @return list of licenses
+ */
+ //public ImmutableList signatures() {
+ // return this.licenses;
+ //}
+
+ @Override
+ public Collection licenses() {
+ return licenses.values();
+ }
+
+ @Override
+ public Set features() {
+ return licenses.keySet();
+ }
+
+ @Override
+ public ESLicense get(FeatureType featureType) {
+ return licenses.get(featureType);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return licenses.values().iterator();
+ }
+
+ /**
+ * Repository metadata factory
+ */
+ public static class Factory implements MetaData.Custom.Factory {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String type() {
+ return TYPE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public LicensesMetaData readFrom(StreamInput in) throws IOException {
+ return new LicensesMetaData(readLicensesFrom(in));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeTo(LicensesMetaData licensesMetaData, StreamOutput out) throws IOException {
+ writeLicensesTo(licensesMetaData, out);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public LicensesMetaData fromXContent(XContentParser parser) throws IOException {
+
+ XContentParser.Token token;
+ List licenses = null;
+ String fieldName = null;
+ while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ if (token == XContentParser.Token.FIELD_NAME) {
+ fieldName = parser.currentName();
+ }
+ if (fieldName != null && fieldName.equals(Fields.LICENSES)) {
+ if (licenses == null) {
+ licenses = new ArrayList<>();
+ }
+ while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
+ licenses.add(licenseFromMap(parser.map()));
+ }
+ }
+ }
+ if (licenses == null) {
+ throw new ElasticsearchParseException("failed to parse licenses: expected ['" + Fields.LICENSES + "']");
+ }
+ return new LicensesMetaData(licenses);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void toXContent(LicensesMetaData licensesMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
+ builder.startObject();
+ builder.startArray(Fields.LICENSES);
+ for (ESLicense license : licensesMetaData.licenses()) {
+ builder.map(licenseAsMap(license));
+ }
+ builder.endArray();
+ builder.endObject();
+ }
+
+ @Override
+ public boolean isPersistent() {
+ return true;
+ }
+
+ /*
+ @Override
+ public EnumSet context() {
+ return MetaData.API_AND_GATEWAY;
+ }*/
+
+
+ private final static class Fields {
+ private static final String LICENSES = "licenses";
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java b/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java
index c190535cfc8..52eb0567f25 100644
--- a/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java
+++ b/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java
@@ -12,9 +12,16 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.license.core.ESLicenses;
+import org.elasticsearch.license.plugin.action.get.GetLicenseAction;
+import org.elasticsearch.license.plugin.action.get.GetLicenseRequest;
+import org.elasticsearch.license.plugin.action.get.GetLicenseResponse;
import org.elasticsearch.rest.*;
+import org.elasticsearch.rest.action.support.AcknowledgedRestListener;
+import org.elasticsearch.rest.action.support.RestBuilderListener;
import static org.elasticsearch.client.Requests.getRepositoryRequest;
+import static org.elasticsearch.license.plugin.action.Utils.licenseAsMap;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.OK;
@@ -28,23 +35,20 @@ public class RestGetLicenseAction extends BaseRestHandler {
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) {
- final String[] repositories = request.paramAsStringArray("repository", Strings.EMPTY_ARRAY);
- //TODO: implement after custom metadata impl
- /*
- GetRepositoriesRequest getRepositoriesRequest = getRepositoryRequest(repositories);
- getRepositoriesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getRepositoriesRequest.masterNodeTimeout()));
- getRepositoriesRequest.local(request.paramAsBoolean("local", getRepositoriesRequest.local()));
- client.admin().cluster().getRepositories(getRepositoriesRequest, new RestBuilderListener(channel) {
- @Override
- public RestResponse buildResponse(GetRepositoriesResponse response, XContentBuilder builder) throws Exception {
- builder.startObject();
- for (RepositoryMetaData repositoryMetaData : response.repositories()) {
- RepositoriesMetaData.FACTORY.toXContent(repositoryMetaData, builder, request);
- }
- builder.endObject();
+ GetLicenseRequest getLicenseRequest = new GetLicenseRequest();
+ client.admin().cluster().execute(GetLicenseAction.INSTANCE, getLicenseRequest, new RestBuilderListener(channel) {
+ @Override
+ public RestResponse buildResponse(GetLicenseResponse getLicenseResponse, XContentBuilder builder) throws Exception {
+ builder.startObject();
+ builder.startArray("licenses");
+ for (ESLicenses.ESLicense license : getLicenseResponse.licenses()) {
+ builder.map(licenseAsMap(license));
+ }
+ builder.endArray();
+ builder.endObject();
return new BytesRestResponse(OK, builder);
}
- });*/
+ });
}
}
diff --git a/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java b/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java
index 612cd1798b1..0acbc9503db 100644
--- a/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java
+++ b/src/main/java/org/elasticsearch/license/plugin/rest/RestPutLicenseAction.java
@@ -35,7 +35,6 @@ public class RestPutLicenseAction extends BaseRestHandler {
PutLicenseRequest putLicenseRequest = new PutLicenseRequest();
putLicenseRequest.listenerThreaded(false);
putLicenseRequest.license(request.content().toUtf8());
- //TODO hookup new action
client.admin().cluster().execute(PutLicenseAction.INSTANCE, putLicenseRequest, new AcknowledgedRestListener(channel));
}
}
diff --git a/src/main/java/org/elasticsearch/license/plugin/service/LicensesService.java b/src/main/java/org/elasticsearch/license/plugin/service/LicensesService.java
new file mode 100644
index 00000000000..90fc21a7c9d
--- /dev/null
+++ b/src/main/java/org/elasticsearch/license/plugin/service/LicensesService.java
@@ -0,0 +1,450 @@
+/*
+ * 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.service;
+
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.cluster.*;
+import org.elasticsearch.cluster.ack.ClusterStateUpdateRequest;
+import org.elasticsearch.cluster.ack.ClusterStateUpdateResponse;
+import org.elasticsearch.cluster.metadata.MetaData;
+import org.elasticsearch.cluster.node.DiscoveryNode;
+import org.elasticsearch.common.component.AbstractComponent;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.inject.Injector;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.license.core.ESLicenses;
+import org.elasticsearch.license.core.LicenseBuilders;
+import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
+import org.elasticsearch.license.plugin.cluster.LicensesMetaData;
+
+/**
+ * Service responsible for maintaining and providing access to snapshot repositories on nodes.
+ */
+public class LicensesService extends AbstractComponent implements ClusterStateListener {
+
+ // private final RepositoryTypesRegistry typesRegistry;
+
+ private final Injector injector;
+
+ private final ClusterService clusterService;
+
+ //private volatile ESLicenses licenses = null;//ImmutableMap.of();
+
+ @Inject
+ public LicensesService(Settings settings, ClusterService clusterService, Injector injector) {
+ super(settings);
+ this.injector = injector;
+ this.clusterService = clusterService;
+ // Doesn't make sense to maintain repositories on non-master and non-data nodes
+ // Nothing happens there anyway
+ if (DiscoveryNode.dataNode(settings) || DiscoveryNode.masterNode(settings)) {
+ clusterService.add(this);
+ }
+ }
+
+ /**
+ * Registers new repository in the cluster
+ *
+ * This method can be only called on the master node. It tries to create a new repository on the master
+ * and if it was successful it adds new repository to cluster metadata.
+ *
+ * @param request register repository request
+ * @param listener register repository listener
+ */
+ public void registerLicenses(final String source, final PutLicenseRequest request, final ActionListener listener) {
+ final LicensesMetaData newLicenseMetaData = new LicensesMetaData(request.license());
+ //TODO: add a source field to request
+ clusterService.submitStateUpdateTask(source, new AckedClusterStateUpdateTask(request, listener) {
+ @Override
+ protected ClusterStateUpdateResponse newResponse(boolean acknowledged) {
+ return new ClusterStateUpdateResponse(acknowledged);
+ }
+
+ @Override
+ public ClusterState execute(ClusterState currentState) throws Exception {
+ // TODO check if newLicenseMetaData actually needs a cluster update
+ MetaData metaData = currentState.metaData();
+ MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
+ LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
+
+ if (currentLicenses == null) {
+ // no licenses were registered
+ currentLicenses = newLicenseMetaData;
+ } else {
+ // merge previous license with new one
+ currentLicenses = new LicensesMetaData(LicenseBuilders.merge(currentLicenses, newLicenseMetaData));
+ }
+ mdBuilder.putCustom(LicensesMetaData.TYPE, currentLicenses);
+ return ClusterState.builder(currentState).metaData(mdBuilder).build();
+ }
+ });
+
+ /*
+ final RepositoryMetaData newRepositoryMetaData = new RepositoryMetaData(request.name, request.type, request.settings);
+
+ clusterService.submitStateUpdateTask(request.cause, new AckedClusterStateUpdateTask(request, listener) {
+ @Override
+ protected ClusterStateUpdateResponse newResponse(boolean acknowledged) {
+ return new ClusterStateUpdateResponse(acknowledged);
+ }
+
+ @Override
+ public ClusterState execute(ClusterState currentState) {
+ ensureRepositoryNotInUse(currentState, request.name);
+ // Trying to create the new repository on master to make sure it works
+ if (!registerLicenses(newRepositoryMetaData)) {
+ // The new repository has the same settings as the old one - ignore
+ return currentState;
+ }
+ MetaData metaData = currentState.metaData();
+ MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
+ RepositoriesMetaData repositories = metaData.custom(RepositoriesMetaData.TYPE);
+ if (repositories == null) {
+ logger.info("put repository [{}]", request.name);
+ repositories = new RepositoriesMetaData(new RepositoryMetaData(request.name, request.type, request.settings));
+ } else {
+ boolean found = false;
+ List repositoriesMetaData = new ArrayList<>(repositories.repositories().size() + 1);
+
+ for (RepositoryMetaData repositoryMetaData : repositories.repositories()) {
+ if (repositoryMetaData.name().equals(newRepositoryMetaData.name())) {
+ found = true;
+ repositoriesMetaData.add(newRepositoryMetaData);
+ } else {
+ repositoriesMetaData.add(repositoryMetaData);
+ }
+ }
+ if (!found) {
+ logger.info("put repository [{}]", request.name);
+ repositoriesMetaData.add(new RepositoryMetaData(request.name, request.type, request.settings));
+ } else {
+ logger.info("update repository [{}]", request.name);
+ }
+ repositories = new RepositoriesMetaData(repositoriesMetaData.toArray(new RepositoryMetaData[repositoriesMetaData.size()]));
+ }
+ mdBuilder.putCustom(RepositoriesMetaData.TYPE, repositories);
+ return ClusterState.builder(currentState).metaData(mdBuilder).build();
+ }
+
+ @Override
+ public void onFailure(String source, Throwable t) {
+ logger.warn("failed to create repository [{}]", t, request.name);
+ super.onFailure(source, t);
+ }
+
+ @Override
+ public boolean mustAck(DiscoveryNode discoveryNode) {
+ return discoveryNode.masterNode();
+ }
+ });*/
+ }
+
+ /**
+ * Unregisters repository in the cluster
+ *
+ * This method can be only called on the master node. It removes repository information from cluster metadata.
+ *
+ * @param request unregister repository request
+ * @param listener unregister repository listener
+ */
+ public void unregisterRepository(final UnregisterRepositoryRequest request, final ActionListener listener) {
+ /*
+ clusterService.submitStateUpdateTask(request.cause, new AckedClusterStateUpdateTask(request, listener) {
+ @Override
+ protected ClusterStateUpdateResponse newResponse(boolean acknowledged) {
+ return new ClusterStateUpdateResponse(acknowledged);
+ }
+
+ @Override
+ public ClusterState execute(ClusterState currentState) {
+ ensureRepositoryNotInUse(currentState, request.name);
+ MetaData metaData = currentState.metaData();
+ MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
+ RepositoriesMetaData repositories = metaData.custom(RepositoriesMetaData.TYPE);
+ if (repositories != null && repositories.repositories().size() > 0) {
+ List repositoriesMetaData = new ArrayList<>(repositories.repositories().size());
+ boolean changed = false;
+ for (RepositoryMetaData repositoryMetaData : repositories.repositories()) {
+ if (Regex.simpleMatch(request.name, repositoryMetaData.name())) {
+ logger.info("delete repository [{}]", repositoryMetaData.name());
+ changed = true;
+ } else {
+ repositoriesMetaData.add(repositoryMetaData);
+ }
+ }
+ if (changed) {
+ repositories = new RepositoriesMetaData(repositoriesMetaData.toArray(new RepositoryMetaData[repositoriesMetaData.size()]));
+ mdBuilder.putCustom(RepositoriesMetaData.TYPE, repositories);
+ return ClusterState.builder(currentState).metaData(mdBuilder).build();
+ }
+ }
+ throw new RepositoryMissingException(request.name);
+ }
+
+ @Override
+ public boolean mustAck(DiscoveryNode discoveryNode) {
+ // Since operation occurs only on masters, it's enough that only master-eligible nodes acked
+ return discoveryNode.masterNode();
+ }
+ });*/
+ }
+
+ /**
+ * Checks if new repositories appeared in or disappeared from cluster metadata and updates current list of
+ * repositories accordingly.
+ *
+ * @param event cluster changed event
+ */
+ @Override
+ public void clusterChanged(ClusterChangedEvent event) {
+ /*
+ try {
+ RepositoriesMetaData oldMetaData = event.previousState().getMetaData().custom(RepositoriesMetaData.TYPE);
+ RepositoriesMetaData newMetaData = event.state().getMetaData().custom(RepositoriesMetaData.TYPE);
+
+ // Check if repositories got changed
+ if ((oldMetaData == null && newMetaData == null) || (oldMetaData != null && oldMetaData.equals(newMetaData))) {
+ return;
+ }
+
+ logger.trace("processing new index repositories for state version [{}]", event.state().version());
+
+ Map survivors = newHashMap();
+ // First, remove repositories that are no longer there
+ for (Map.Entry entry : repositories.entrySet()) {
+ if (newMetaData == null || newMetaData.repository(entry.getKey()) == null) {
+ logger.debug("unregistering repository [{}]", entry.getKey());
+ closeRepository(entry.getKey(), entry.getValue());
+ } else {
+ survivors.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ ImmutableMap.Builder builder = ImmutableMap.builder();
+ if (newMetaData != null) {
+ // Now go through all repositories and update existing or create missing
+ for (RepositoryMetaData repositoryMetaData : newMetaData.repositories()) {
+ RepositoryHolder holder = survivors.get(repositoryMetaData.name());
+ if (holder != null) {
+ // Found previous version of this repository
+ if (!holder.type.equals(repositoryMetaData.type()) || !holder.settings.equals(repositoryMetaData.settings())) {
+ // Previous version is different from the version in settings
+ logger.debug("updating repository [{}]", repositoryMetaData.name());
+ closeRepository(repositoryMetaData.name(), holder);
+ holder = createRepositoryHolder(repositoryMetaData);
+ }
+ } else {
+ holder = createRepositoryHolder(repositoryMetaData);
+ }
+ if (holder != null) {
+ logger.debug("registering repository [{}]", repositoryMetaData.name());
+ builder.put(repositoryMetaData.name(), holder);
+ }
+ }
+ }
+ repositories = builder.build();
+ } catch (Throwable ex) {
+ logger.warn("failure updating cluster state ", ex);
+ }*/
+ }
+
+
+ /**
+ * Returns registered repository
+ *
+ * This method is called only on the master node
+ *
+ * @param repository repository name
+ * @return registered repository
+ * @throws RepositoryMissingException if repository with such name isn't registered
+ */
+ /*
+ public Repository repository(String repository) {
+ RepositoryHolder holder = repositories.get(repository);
+ if (holder != null) {
+ return holder.repository;
+ }
+ throw new RepositoryMissingException(repository);
+ }*/
+
+ /**
+ * Returns registered index shard repository
+ *
+ * This method is called only on data nodes
+ *
+ * @param repository repository name
+ * @return registered repository
+ * @throws RepositoryMissingException if repository with such name isn't registered
+ */
+ /*
+ public IndexShardRepository indexShardRepository(String repository) {
+ RepositoryHolder holder = repositories.get(repository);
+ if (holder != null) {
+ return holder.indexShardRepository;
+ }
+ throw new RepositoryMissingException(repository);
+ }*/
+
+ /**
+ * Creates a new repository and adds it to the list of registered repositories.
+ *
+ * If a repository with the same name but different types or settings already exists, it will be closed and
+ * replaced with the new repository. If a repository with the same name exists but it has the same type and settings
+ * the new repository is ignored.
+ *
+ * @param repositoryMetaData new repository metadata
+ * @return {@code true} if new repository was added or {@code false} if it was ignored
+ */
+ /*
+ private boolean registerLicenses(RepositoryMetaData repositoryMetaData) {
+ RepositoryHolder previous = repositories.get(repositoryMetaData.name());
+ if (previous != null) {
+ if (!previous.type.equals(repositoryMetaData.type()) && previous.settings.equals(repositoryMetaData.settings())) {
+ // Previous version is the same as this one - ignore it
+ return false;
+ }
+ }
+ RepositoryHolder holder = createRepositoryHolder(repositoryMetaData);
+ if (previous != null) {
+ // Closing previous version
+ closeRepository(repositoryMetaData.name(), previous);
+ }
+ Map newRepositories = newHashMap(repositories);
+ newRepositories.put(repositoryMetaData.name(), holder);
+ repositories = ImmutableMap.copyOf(newRepositories);
+ return true;
+ }
+*/
+ /**
+ * Closes the repository
+ *
+ * @param name repository name
+ * @param holder repository holder
+ */
+ /*
+ private void closeRepository(String name, RepositoryHolder holder) {
+ logger.debug("closing repository [{}][{}]", holder.type, name);
+ if (holder.injector != null) {
+ Injectors.close(holder.injector);
+ }
+ if (holder.repository != null) {
+ holder.repository.close();
+ }
+ }*/
+
+ /**
+ * Creates repository holder
+ */
+ /*
+ private RepositoryHolder createRepositoryHolder(RepositoryMetaData repositoryMetaData) {
+ logger.debug("creating repository [{}][{}]", repositoryMetaData.type(), repositoryMetaData.name());
+ Injector repositoryInjector = null;
+ try {
+ ModulesBuilder modules = new ModulesBuilder();
+ RepositoryName name = new RepositoryName(repositoryMetaData.type(), repositoryMetaData.name());
+ modules.add(new RepositoryNameModule(name));
+ modules.add(new RepositoryModule(name, repositoryMetaData.settings(), this.settings, typesRegistry));
+
+ repositoryInjector = modules.createChildInjector(injector);
+ Repository repository = repositoryInjector.getInstance(Repository.class);
+ IndexShardRepository indexShardRepository = repositoryInjector.getInstance(IndexShardRepository.class);
+ repository.start();
+ return new RepositoryHolder(repositoryMetaData.type(), repositoryMetaData.settings(), repositoryInjector, repository, indexShardRepository);
+ } catch (Throwable t) {
+ if (repositoryInjector != null) {
+ Injectors.close(repositoryInjector);
+ }
+ logger.warn("failed to create repository [{}][{}]", t, repositoryMetaData.type(), repositoryMetaData.name());
+ throw new RepositoryException(repositoryMetaData.name(), "failed to create repository", t);
+ }
+ }
+
+ private void ensureRepositoryNotInUse(ClusterState clusterState, String repository) {
+ if (SnapshotsService.isRepositoryInUse(clusterState, repository) || RestoreService.isRepositoryInUse(clusterState, repository)) {
+ throw new ElasticsearchIllegalStateException("trying to modify or unregister repository that is currently used ");
+ }
+ }*/
+
+ /**
+ * Internal data structure for holding repository with its configuration information and injector
+ */
+ /* private static class RepositoryHolder {
+
+ private final String type;
+ private final Settings settings;
+ private final Injector injector;
+ private final Repository repository;
+ private final IndexShardRepository indexShardRepository;
+
+ public RepositoryHolder(String type, Settings settings, Injector injector, Repository repository, IndexShardRepository indexShardRepository) {
+ this.type = type;
+ this.settings = settings;
+ this.repository = repository;
+ this.indexShardRepository = indexShardRepository;
+ this.injector = injector;
+ }
+ }
+*/
+ /**
+ * Register repository request
+ */
+ public static class RegisterRepositoryRequest extends ClusterStateUpdateRequest {
+
+ final String cause;
+
+ final String name;
+
+ final String type;
+
+ Settings settings = null;
+
+ /**
+ * Constructs new register repository request
+ *
+ * @param cause repository registration cause
+ * @param name repository name
+ * @param type repository type
+ */
+ public RegisterRepositoryRequest(String cause, String name, String type) {
+ this.cause = cause;
+ this.name = name;
+ this.type = type;
+ }
+
+ /**
+ * Sets repository settings
+ *
+ * @param settings repository settings
+ * @return this request
+ */
+ public RegisterRepositoryRequest settings(Settings settings) {
+ this.settings = settings;
+ return this;
+ }
+ }
+
+ /**
+ * Unregister repository request
+ */
+ public static class UnregisterRepositoryRequest extends ClusterStateUpdateRequest {
+
+ final String cause;
+
+ final String name;
+
+ /**
+ * Creates a new unregister repository request
+ *
+ * @param cause repository unregistration cause
+ * @param name repository name
+ */
+ public UnregisterRepositoryRequest(String cause, String name) {
+ this.cause = cause;
+ this.name = name;
+ }
+
+ }
+}
diff --git a/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java b/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java
new file mode 100644
index 00000000000..c9382dbec79
--- /dev/null
+++ b/src/test/java/org/elasticsearch/license/plugin/LicenseTransportTests.java
@@ -0,0 +1,85 @@
+/*
+ * 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.ActionFuture;
+import org.elasticsearch.cluster.metadata.MetaData;
+import org.elasticsearch.license.TestUtils;
+import org.elasticsearch.license.core.ESLicenses;
+import org.elasticsearch.license.licensor.tools.KeyPairGeneratorTool;
+import org.elasticsearch.license.plugin.action.put.PutLicenseAction;
+import org.elasticsearch.license.plugin.action.put.PutLicenseRequest;
+import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
+import org.elasticsearch.license.plugin.cluster.LicensesMetaData;
+import org.elasticsearch.test.ElasticsearchIntegrationTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class LicenseTransportTests extends ElasticsearchIntegrationTest {
+
+ static {
+ MetaData.registerFactory(LicensesMetaData.TYPE, LicensesMetaData.FACTORY);
+ }
+
+ private static String pubKeyPath = null;
+ private static String priKeyPath = null;
+ private static String keyPass = null;
+
+ @BeforeClass
+ public static void setup() throws IOException {
+
+ // Generate temp KeyPair spec
+ File privateKeyFile = File.createTempFile("privateKey", ".key");
+ File publicKeyFile = File.createTempFile("publicKey", ".key");
+ LicenseTransportTests.pubKeyPath = publicKeyFile.getAbsolutePath();
+ LicenseTransportTests.priKeyPath = privateKeyFile.getAbsolutePath();
+ assert privateKeyFile.delete();
+ assert publicKeyFile.delete();
+ String keyPass = "password";
+ LicenseTransportTests.keyPass = keyPass;
+
+ // Generate keyPair
+ String[] args = new String[6];
+ args[0] = "--publicKeyPath";
+ args[1] = LicenseTransportTests.pubKeyPath;
+ args[2] = "--privateKeyPath";
+ args[3] = LicenseTransportTests.priKeyPath;
+ args[4] = "--keyPass";
+ args[5] = LicenseTransportTests.keyPass;
+ KeyPairGeneratorTool.main(args);
+ }
+
+ @Test
+ public void testPutLicense() throws ParseException, ExecutionException, InterruptedException {
+
+ Map map = new HashMap<>();
+ TestUtils.FeatureAttributes featureAttributes =
+ new TestUtils.FeatureAttributes("shield", "subscription", "platinum", "foo bar Inc.", "elasticsearch", 2, "2014-12-13", "2015-12-13");
+ map.put(ESLicenses.FeatureType.SHIELD, featureAttributes);
+
+ String licenseString = TestUtils.generateESLicenses(map);
+
+ PutLicenseRequest putLicenseRequest = new PutLicenseRequest();
+ putLicenseRequest.license(licenseString);
+
+ final ActionFuture execute = client().admin().cluster().execute(PutLicenseAction.INSTANCE, putLicenseRequest);
+
+ final PutLicenseResponse putLicenseResponse = execute.get();
+
+ assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
+
+ }
+}