second iteration

Original commit: elastic/x-pack-elasticsearch@bc5725d804
This commit is contained in:
Areek Zillur 2014-10-03 10:39:50 -04:00
parent 01af8a39e6
commit bee849d5f4
17 changed files with 1011 additions and 106 deletions

135
pom.xml
View File

@ -10,11 +10,18 @@
<properties>
<elasticsearch.version>1.4.0-SNAPSHOT</elasticsearch.version>
<lucene.version>4.10.0</lucene.version>
</properties>
<dependencies>
<!-- test deps -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-test-framework</artifactId>
<version>${lucene.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
@ -22,13 +29,24 @@
<scope>test</scope>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.carrotsearch.randomizedtesting</groupId>
<artifactId>randomizedtesting-runner</artifactId>
<version>2.1.2</version>
<scope>test</scope>
</dependency>
<!-- actual deps -->
<dependency>
@ -147,6 +165,121 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.carrotsearch.randomizedtesting</groupId>
<artifactId>junit4-maven-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>tests</id>
<phase>test</phase>
<goals>
<goal>junit4</goal>
</goals>
<configuration>
<heartbeat>20</heartbeat>
<jvmOutputAction>pipe,warn</jvmOutputAction>
<leaveTemporary>true</leaveTemporary>
<listeners>
<report-ant-xml mavenExtensions="true"
dir="${project.build.directory}/surefire-reports"/>
<report-text
showThrowable="true"
showStackTraces="true"
showOutput="${tests.output}"
showStatusOk="false"
showStatusError="true"
showStatusFailure="true"
showStatusIgnored="true"
showSuiteSummary="true"
timestamps="false"/>
<report-execution-times historyLength="20" file="${basedir}/${execution.hint.file}"/>
</listeners>
<assertions>
<enable/>
<disable package="${tests.assertion.disabled}"/>
<!-- pass org.elasticsearch to run without assertions -->
</assertions>
<parallelism>${tests.jvms}</parallelism>
<balancers>
<execution-times>
<fileset dir="${basedir}" includes="${execution.hint.file}"/>
</execution-times>
</balancers>
<includes>
<include>**/*Tests.class</include>
<include>**/*Test.class</include>
</includes>
<excludes>
<exclude>**/Abstract*.class</exclude>
<exclude>**/*StressTest.class</exclude>
</excludes>
<jvmArgs>
<param>-Xmx${tests.heap.size}</param>
<param>-Xms${tests.heap.size}</param>
<param>-Xss256k</param>
<param>-XX:MaxPermSize=128m</param>
<param>-XX:MaxDirectMemorySize=512m</param>
<param>-Des.logger.prefix=</param>
<param>-XX:+HeapDumpOnOutOfMemoryError</param>
<param>-XX:HeapDumpPath=${tests.heapdump.path}</param>
</jvmArgs>
<shuffleOnSlave>${tests.shuffle}</shuffleOnSlave>
<sysouts>${tests.verbose}</sysouts>
<seed>${tests.seed}</seed>
<haltOnFailure>${tests.failfast}</haltOnFailure>
<uniqueSuiteNames>false</uniqueSuiteNames>
<systemProperties>
<java.io.tmpdir>.</java.io.tmpdir>
<!-- we use '.' since this is different per JVM-->
<!-- RandomizedTesting library system properties -->
<tests.bwc>${tests.bwc}</tests.bwc>
<tests.bwc.path>${tests.bwc.path}</tests.bwc.path>
<tests.bwc.version>${tests.bwc.version}</tests.bwc.version>
<tests.jvm.argline>${tests.jvm.argline}</tests.jvm.argline>
<tests.processors>${tests.processors}</tests.processors>
<tests.appendseed>${tests.appendseed}</tests.appendseed>
<tests.iters>${tests.iters}</tests.iters>
<tests.maxfailures>${tests.maxfailures}</tests.maxfailures>
<tests.failfast>${tests.failfast}</tests.failfast>
<tests.class>${tests.class}</tests.class>
<tests.method>${tests.method}</tests.method>
<tests.nightly>${tests.nightly}</tests.nightly>
<tests.verbose>${tests.verbose}</tests.verbose>
<tests.badapples>${tests.badapples}</tests.badapples>
<tests.weekly>${tests.weekly}</tests.weekly>
<tests.slow>${tests.slow}</tests.slow>
<tests.awaitsfix>${tests.awaitsfix}</tests.awaitsfix>
<tests.slow>${tests.slow}</tests.slow>
<tests.timeoutSuite>${tests.timeoutSuite}</tests.timeoutSuite>
<tests.showSuccess>${tests.showSuccess}</tests.showSuccess>
<tests.integration>${tests.integration}</tests.integration>
<tests.client.ratio>${tests.client.ratio}</tests.client.ratio>
<tests.enable_mock_modules>${tests.enable_mock_modules}</tests.enable_mock_modules>
<tests.assertion.disabled>${tests.assertion.disabled}</tests.assertion.disabled>
<tests.rest>${tests.rest}</tests.rest>
<tests.rest.suite>${tests.rest.suite}</tests.rest.suite>
<tests.rest.blacklist>${tests.rest.blacklist}</tests.rest.blacklist>
<tests.rest.spec>${tests.rest.spec}</tests.rest.spec>
<tests.network>${tests.network}</tests.network>
<tests.cluster>${tests.cluster}</tests.cluster>
<tests.heap.size>${tests.heap.size}</tests.heap.size>
<tests.filter>${tests.filter}</tests.filter>
<tests.version>${project.version}</tests.version>
<es.node.local>${env.ES_TEST_LOCAL}</es.node.local>
<es.node.mode>${es.node.mode}</es.node.mode>
<es.logger.level>${es.logger.level}</es.logger.level>
<tests.security.manager>${tests.security.manager}</tests.security.manager>
<tests.compatibility>${tests.compatibility}</tests.compatibility>
<java.awt.headless>true</java.awt.headless>
<!-- everything below is for security manager / test.policy -->
<junit4.tempDir>${project.build.directory}</junit4.tempDir>
<java.security.policy>${basedir}/dev-tools/tests.policy</java.security.policy>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@ -50,7 +50,7 @@ public class LicenseBuilders {
}
public static class LicensesBuilder {
private Map<FeatureType, ESLicense> licenseMap;
private Map<FeatureType, ESLicense> 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<ESLicense> 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

View File

@ -23,7 +23,7 @@ public class Utils {
private Utils() {
}
static ESLicenses getESLicensesFromSignatures(final LicenseManager licenseManager, Set<String> signatures) {
public static ESLicenses getESLicensesFromSignatures(final LicenseManager licenseManager, Set<String> signatures) {
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
for (String signature : signatures) {
licensesBuilder.license(getESLicenseFromSignature(licenseManager, signature));

View File

@ -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)
}

View File

@ -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 {
}

View File

@ -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<String, Object> licenseAsMap(ESLicense esLicense) {
ImmutableMap.Builder<String, Object> 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<String, Object> 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";
}
}

View File

@ -16,19 +16,12 @@ import java.io.IOException;
public class GetLicenseRequest extends MasterNodeReadOperationRequest<GetLicenseRequest> {
GetLicenseRequest() {
public GetLicenseRequest() {
}
@Override
public ActionRequestValidationException validate() {
return null;
/*ActionRequestValidationException validationException = null;
if (repositories == null) {
validationException = addValidationError("repositories is null", validationException);
}
return validationException;
*/
}
@Override

View File

@ -12,7 +12,7 @@ import org.elasticsearch.client.ClusterAdminClient;
public class GetLicenseRequestBuilder extends MasterNodeReadOperationRequestBuilder<GetLicenseRequest, GetLicenseResponse, GetLicenseRequestBuilder, ClusterAdminClient> {
/**
* Creates new get repository request builder
* Creates new get licenses request builder
*
* @param clusterAdminClient cluster admin client
*/

View File

@ -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<RepositoryMetaData> {
import static org.elasticsearch.license.plugin.action.Utils.readLicensesFrom;
import static org.elasticsearch.license.plugin.action.Utils.writeLicensesTo;
//TODO: use LicenseMetaData instead
private ImmutableList<RepositoryMetaData> repositories = ImmutableList.of();
public class GetLicenseResponse extends ActionResponse {
private ESLicenses licenses = null;
GetLicenseResponse() {
}
GetLicenseResponse(ImmutableList<RepositoryMetaData> repositories) {
this.repositories = repositories;
GetLicenseResponse(ESLicenses esLicenses) {
this.licenses = esLicenses;
}
/**
* List of repositories to return
*
* @return list or repositories
*/
public ImmutableList<RepositoryMetaData> 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<RepositoryMetaData> 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<RepositoryMetaData> iterator() {
return repositories.iterator();
}
}

View File

@ -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<GetLicenseResponse> 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.<RepositoryMetaData>of()));
}
} else {
if (repositories != null) {
ImmutableList.Builder<RepositoryMetaData> 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));
}
}

View File

@ -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<PutLicenseRequest> {
private ESLicenses license;
@ -61,14 +64,14 @@ public class PutLicenseRequest extends AcknowledgedRequest<PutLicenseRequest> {
@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);
}
}

View File

@ -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<PutLicenseRequest, PutLicenseResponse> {
//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<PutLicenseResponse> listener) throws ElasticsearchException {
//TODO
licensesService.registerLicenses("put_licenses []",request, new ActionListener<ClusterStateUpdateResponse>() {
@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<ClusterStateUpdateResponse>() {

View File

@ -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<FeatureType, ESLicense> licenses;
/**
* Constructs new repository metadata
*
* @param esLicenses list of esLicense
*/
public LicensesMetaData(List<ESLicense> esLicenses) {
this.licenses = map(esLicenses);
}
public LicensesMetaData(ESLicenses esLicenses) {
this.licenses = map(esLicenses);
}
private static ImmutableMap<FeatureType, ESLicense> map(Iterable<ESLicense> esLicenses) {
final ImmutableMap.Builder<FeatureType, ESLicense> 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<String> signatures() {
// return this.licenses;
//}
@Override
public Collection<ESLicense> licenses() {
return licenses.values();
}
@Override
public Set<FeatureType> features() {
return licenses.keySet();
}
@Override
public ESLicense get(FeatureType featureType) {
return licenses.get(featureType);
}
@Override
public Iterator<ESLicense> iterator() {
return licenses.values().iterator();
}
/**
* Repository metadata factory
*/
public static class Factory implements MetaData.Custom.Factory<LicensesMetaData> {
/**
* {@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<ESLicense> 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<MetaData.XContentContext> context() {
return MetaData.API_AND_GATEWAY;
}*/
private final static class Fields {
private static final String LICENSES = "licenses";
}
}
}

View File

@ -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<GetRepositoriesResponse>(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<GetLicenseResponse>(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);
}
});*/
});
}
}

View File

@ -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<PutLicenseResponse>(channel));
}
}

View File

@ -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
* <p/>
* 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<ClusterStateUpdateResponse> listener) {
final LicensesMetaData newLicenseMetaData = new LicensesMetaData(request.license());
//TODO: add a source field to request
clusterService.submitStateUpdateTask(source, new AckedClusterStateUpdateTask<ClusterStateUpdateResponse>(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<ClusterStateUpdateResponse>(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<RepositoryMetaData> 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
* <p/>
* 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<ClusterStateUpdateResponse> listener) {
/*
clusterService.submitStateUpdateTask(request.cause, new AckedClusterStateUpdateTask<ClusterStateUpdateResponse>(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<RepositoryMetaData> 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<String, RepositoryHolder> survivors = newHashMap();
// First, remove repositories that are no longer there
for (Map.Entry<String, RepositoryHolder> 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<String, RepositoryHolder> 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
* <p/>
* 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
* <p/>
* 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.
* <p/>
* 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<String, RepositoryHolder> 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<RegisterRepositoryRequest> {
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<UnregisterRepositoryRequest> {
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;
}
}
}

View File

@ -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<ESLicenses.FeatureType, TestUtils.FeatureAttributes> 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<PutLicenseResponse> execute = client().admin().cluster().execute(PutLicenseAction.INSTANCE, putLicenseRequest);
final PutLicenseResponse putLicenseResponse = execute.get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
}
}