metaData fixes; Initial licneseClientService; trial license encoding/decoding

Original commit: elastic/x-pack-elasticsearch@6913a4dc23
This commit is contained in:
Areek Zillur 2014-10-14 13:21:42 -04:00
parent a8f5f0151d
commit 52d29f4fbb
15 changed files with 280 additions and 145 deletions

View File

@ -32,8 +32,7 @@ import static org.elasticsearch.license.manager.ESLicenseProvider.extractSignedL
* and querying against licenses on a feature basis
* <p/>
* TODO:
* - integration with cluster state
* - use ESLicenseProvider to query license from cluster state
* - make it into a guice singleton
*/
public class ESLicenseManager {
@ -61,7 +60,8 @@ public class ESLicenseManager {
public static ESLicenseManager createClusterStateBasedInstance(ClusterService clusterService, String publicKeyPath) {
if (ESLicenseManager.instance == null) {
ESLicenseManager.publicKeyDataProvider = new FilePublicKeyDataProvider(publicKeyPath);
return new ESLicenseManager(ESLicenseProvider.createClusterBasedLicenseProvider(clusterService, publicKeyPath));
instance = new ESLicenseManager(ESLicenseProvider.createClusterBasedLicenseProvider(clusterService, publicKeyPath));
return instance;
} else if (ESLicenseManager.instance.licenseProvider instanceof ClusterStateLicenseProvider) {
return ESLicenseManager.instance;
} else {

View File

@ -8,6 +8,7 @@ package org.elasticsearch.license.manager;
import net.nicholaswilliams.java.licensing.ObjectSerializer;
import net.nicholaswilliams.java.licensing.SignedLicense;
import org.apache.commons.codec.binary.Base64;
import org.elasticsearch.common.collect.Sets;
import org.elasticsearch.license.core.ESLicenses;
import org.elasticsearch.license.core.LicenseBuilders;
@ -19,15 +20,9 @@ import static org.elasticsearch.license.core.ESLicenses.ESLicense;
public class Utils {
public static ESLicenses getESLicensesFromSignatures(final Set<String> signatures) {
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
for (String signature : signatures) {
licensesBuilder.license(getESLicenseFromSignature(signature));
}
return licensesBuilder.build();
}
private static ESLicense getESLicenseFromSignature(String signature) {
public static ESLicense getESLicenseFromSignature(String signature) {
byte[] signatureBytes = Base64.decodeBase64(signature);
ByteBuffer byteBuffer = ByteBuffer.wrap(signatureBytes);
byteBuffer = (ByteBuffer) byteBuffer.position(13);

View File

@ -7,6 +7,7 @@ package org.elasticsearch.license.plugin;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Scopes;
import org.elasticsearch.license.manager.ESLicenseManager;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesService;
@ -14,6 +15,7 @@ public class LicenseModule extends AbstractModule {
@Override
protected void configure() {
//TODO: bind LicensesManagementService and LicensesValidationService to LicensesServices instead
//bind(ESLicenseManager.class).asEagerSingleton();
bind(LicensesService.class).in(Scopes.SINGLETON);
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.license.plugin.action;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.Sets;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.license.core.ESLicenses;
@ -14,13 +15,85 @@ import org.elasticsearch.license.plugin.core.TrialLicenses;
import org.elasticsearch.license.plugin.core.TrialLicensesBuilder;
import java.io.IOException;
import java.util.Map;
import java.util.*;
import static org.elasticsearch.license.core.ESLicenses.*;
import static org.elasticsearch.license.manager.Utils.getESLicenseFromSignature;
import static org.elasticsearch.license.plugin.core.TrialLicenses.TrialLicense;
import static org.elasticsearch.license.plugin.core.TrialLicensesBuilder.fromEncodedTrialLicense;
import static org.elasticsearch.license.plugin.core.TrialLicensesBuilder.toEncodedTrialLicense;
import static org.elasticsearch.license.plugin.core.TrialLicensesBuilder.trialLicensesBuilder;
public class Utils {
public static ESLicenses readGeneratedLicensesFromMetaData(StreamInput in) throws IOException {
boolean exists = in.readBoolean();
return exists ? fromSignatures(in.readStringArray()) : null;
}
public static void writeGeneratedLicensesToMetaData(ESLicenses esLicenses, StreamOutput out) throws IOException {
if (esLicenses == null) {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
out.writeStringArray(toSignatures(esLicenses));
}
}
public static TrialLicenses readTrialLicensesFromMetaData(StreamInput in) throws IOException {
boolean exists = in.readBoolean();
return exists ? fromEncodedTrialLicenses(in.readStringArray()) : null;
}
public static void writeTrialLicensesToMetaData(TrialLicenses trialLicenses, StreamOutput out) throws IOException {
if (trialLicenses == null) {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
out.writeStringArray(toEncodedTrialLicenses(trialLicenses));
}
}
public static String[] toEncodedTrialLicenses(TrialLicenses trialLicenses) {
Set<String> encodedTrialLicenses = new HashSet<>();
for (TrialLicense trialLicense : trialLicenses) {
encodedTrialLicenses.add(toEncodedTrialLicense(trialLicense));
}
return encodedTrialLicenses.toArray(new String[encodedTrialLicenses.size()]);
}
public static TrialLicenses fromEncodedTrialLicenses(String[] encodedTrialLicenses) {
final TrialLicensesBuilder trialLicensesBuilder = trialLicensesBuilder();
for (String encodedTrialLicense : encodedTrialLicenses) {
trialLicensesBuilder.license(fromEncodedTrialLicense(encodedTrialLicense));
}
return trialLicensesBuilder.build();
}
public static TrialLicenses fromEncodedTrialLicenses(Set<String> encodedTrialLicenses) {
return fromEncodedTrialLicenses(encodedTrialLicenses.toArray(new String[encodedTrialLicenses.size()]));
}
public static String[] toSignatures(ESLicenses esLicenses) {
Set<String> signatures = new HashSet<>();
for (ESLicense esLicense : esLicenses) {
signatures.add(esLicense.signature());
}
return signatures.toArray(new String[signatures.size()]);
}
public static ESLicenses fromSignatures(final String[] signatures) {
return fromSignatures(Sets.newHashSet(signatures));
}
public static ESLicenses fromSignatures(final Set<String> signatures) {
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
for (String signature : signatures) {
licensesBuilder.license(getESLicenseFromSignature(signature));
}
return licensesBuilder.build();
}
public static ESLicenses readGeneratedLicensesFrom(StreamInput in) throws IOException {
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
@ -72,19 +145,24 @@ public class Utils {
}
}
// TODO: make sure field order is preserved
public static Map<String, Object> trialLicenseAsMap(TrialLicense trialLicense) {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.put(TrialLicenseFields.UID, trialLicense.uid());
builder.put(TrialLicenseFields.TYPE, Type.TRIAL.string());
builder.put(TrialLicenseFields.SUBSCRIPTION_TYPE, SubscriptionType.NONE.string());
builder.put(TrialLicenseFields.ISSUE_DATE, trialLicense.issueDate());
builder.put(TrialLicenseFields.FEATURE, trialLicense.feature().string());
builder.put(TrialLicenseFields.EXPIRY_DATE, trialLicense.expiryDate());
builder.put(TrialLicenseFields.MAX_NODES, trialLicense.maxNodes());
builder.put(TrialLicenseFields.FEATURE, trialLicense.feature().string());
builder.put(TrialLicenseFields.ISSUED_TO, trialLicense.issuedTo());
return builder.build();
}
public static TrialLicense trialLicenseFromMap(Map<String, Object> map) {
return TrialLicensesBuilder.trialLicenseBuilder()
.uid((String) map.get(TrialLicenseFields.UID))
.issuedTo((String) map.get(TrialLicenseFields.ISSUED_TO))
.maxNodes((int) map.get(TrialLicenseFields.MAX_NODES))
.feature(FeatureType.fromString((String) map.get(TrialLicenseFields.FEATURE)))
.issueDate((long) map.get(TrialLicenseFields.ISSUE_DATE))
@ -93,6 +171,7 @@ public class Utils {
}
// TODO: make sure field order is preserved
public static Map<String, Object> licenseAsMap(ESLicense esLicense) {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.put(LicenseFields.UID, esLicense.uid());
@ -124,11 +203,13 @@ public class Utils {
final static class TrialLicenseFields {
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 EXPIRY_DATE = "expiry_date";
private final static String MAX_NODES = "max_nodes";
private final static String FEATURE = "feature";
private final static String ISSUED_TO = "issued_to";
private final static String MAX_NODES = "max_nodes";
private final static String EXPIRY_DATE = "expiry_date";
}
final static class LicenseFields {

View File

@ -10,37 +10,46 @@ 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 org.elasticsearch.license.plugin.core.TrialLicenses;
import org.elasticsearch.license.plugin.core.TrialLicensesBuilder;
import java.io.IOException;
import static org.elasticsearch.license.plugin.action.Utils.readGeneratedLicensesFrom;
import static org.elasticsearch.license.plugin.action.Utils.writeGeneratedLicensesTo;
import static org.elasticsearch.license.plugin.action.Utils.*;
public class GetLicenseResponse extends ActionResponse {
private ESLicenses licenses = null;
private TrialLicenses trialLicenses = null;
GetLicenseResponse() {
}
GetLicenseResponse(ESLicenses esLicenses) {
GetLicenseResponse(ESLicenses esLicenses, TrialLicenses trialLicenses) {
this.licenses = esLicenses;
this.trialLicenses = trialLicenses;
}
public ESLicenses licenses() {
return (licenses != null) ? licenses : LicenseBuilders.licensesBuilder().build();
}
public TrialLicenses trialLicenses() {
return trialLicenses != null ? trialLicenses : TrialLicensesBuilder.EMPTY;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
licenses = readGeneratedLicensesFrom(in);
trialLicenses = readTrialLicensesFrom(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
writeGeneratedLicensesTo(licenses, out);
writeTrialLicensesTo(trialLicenses, out);
}
}

View File

@ -54,7 +54,7 @@ public class TransportGetLicenseAction extends TransportMasterNodeReadOperationA
MetaData metaData = state.metaData();
LicensesMetaData licenses = metaData.custom(LicensesMetaData.TYPE);
if (licenses != null) {
listener.onResponse(new GetLicenseResponse(licenses.getLicenses()));
listener.onResponse(new GetLicenseResponse(licenses.getLicenses(), licenses.getTrialLicenses()));
} else {
listener.onResponse(new GetLicenseResponse());
}

View File

@ -0,0 +1,21 @@
/*
* 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.core;
import org.elasticsearch.common.inject.ImplementedBy;
@ImplementedBy(LicensesService.class)
public interface LicensesClientService {
interface Listener {
void onEnabled();
void onDisabled();
}
void registerAndActivate(String feature, LicensesService.TrialLicenseOptions trialLicenseOptions, Listener listener);
}

View File

@ -5,29 +5,22 @@
*/
package org.elasticsearch.license.plugin.core;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
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 org.elasticsearch.license.core.LicenseBuilders;
import java.io.IOException;
import java.util.*;
import static org.elasticsearch.license.core.ESLicenses.ESLicense;
import static org.elasticsearch.license.core.ESLicenses.FeatureType;
import static org.elasticsearch.license.plugin.action.Utils.*;
import static org.elasticsearch.license.plugin.core.TrialLicenses.TrialLicense;
/**
* Contains metadata about registered licenses
*
* TODO: store only signatures rather than the whole licenses json in cluster state
*/
public class LicensesMetaData implements MetaData.Custom {
@ -35,9 +28,9 @@ public class LicensesMetaData implements MetaData.Custom {
public static final Factory FACTORY = new Factory();
private final ImmutableMap<FeatureType, ESLicense> licensesMap;
private final ESLicenses licenses;
private final ImmutableMap<FeatureType, TrialLicense> trialLicensesMap;
private final TrialLicenses trialLicenses;
/**
* Constructs new licenses metadata
@ -45,73 +38,17 @@ public class LicensesMetaData implements MetaData.Custom {
* @param esLicenses list of esLicense
*/
public LicensesMetaData(ESLicenses esLicenses, TrialLicenses trialLicenses) {
this.licensesMap = map(esLicenses);
this.trialLicensesMap = map(trialLicenses);
this.licenses = esLicenses;
this.trialLicenses = trialLicenses;
}
public ESLicenses getLicenses() {
return new ESLicenses() {
@Override
public Collection<ESLicense> licenses() {
return licensesMap.values();
}
@Override
public Set<FeatureType> features() {
return licensesMap.keySet();
}
@Override
public ESLicense get(FeatureType featureType) {
return licensesMap.get(featureType);
}
@Override
public Iterator<ESLicense> iterator() {
return licensesMap.values().iterator();
}
};
return licenses;
}
public TrialLicenses getTrialLicenses() {
return new TrialLicenses() {
@Override
public Collection<TrialLicense> trialLicenses() {
return trialLicensesMap.values();
}
@Override
public TrialLicense getTrialLicense(FeatureType featureType) {
return trialLicensesMap.get(featureType);
}
@Override
public Iterator<TrialLicense> iterator() {
return trialLicensesMap.values().iterator();
}
};
}
private static ImmutableMap<FeatureType, ESLicense> map(ESLicenses esLicenses) {
final ImmutableMap.Builder<FeatureType, ESLicense> builder = ImmutableMap.builder();
if (esLicenses != null) {
for (ESLicense esLicense : esLicenses) {
builder.put(esLicense.feature(), esLicense);
}
}
return builder.build();
}
private static ImmutableMap<FeatureType, TrialLicense> map(TrialLicenses trialLicenses) {
final ImmutableMap.Builder<FeatureType, TrialLicense> builder = ImmutableMap.builder();
if (trialLicenses != null) {
for (TrialLicense esLicense : trialLicenses) {
builder.put(esLicense.feature(), esLicense);
}
}
return builder.build();
return trialLicenses;
}
/**
@ -135,8 +72,8 @@ public class LicensesMetaData implements MetaData.Custom {
ESLicenses esLicenses = null;
TrialLicenses trialLicenses = null;
if (in.readBoolean()) {
esLicenses = readGeneratedLicensesFrom(in);
trialLicenses = readTrialLicensesFrom(in);
esLicenses = readGeneratedLicensesFromMetaData(in);
trialLicenses = readTrialLicensesFromMetaData(in);
}
return new LicensesMetaData(esLicenses, trialLicenses);
}
@ -150,8 +87,8 @@ public class LicensesMetaData implements MetaData.Custom {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
writeGeneratedLicensesTo(licensesMetaData.getLicenses(), out);
writeTrialLicensesTo(licensesMetaData.getTrialLicenses(), out);
writeGeneratedLicensesToMetaData(licensesMetaData.getLicenses(), out);
writeTrialLicensesToMetaData(licensesMetaData.getTrialLicenses(), out);
}
}
@ -162,9 +99,9 @@ public class LicensesMetaData implements MetaData.Custom {
public LicensesMetaData fromXContent(XContentParser parser) throws IOException {
XContentParser.Token token;
final LicenseBuilders.LicensesBuilder licensesBuilder = LicenseBuilders.licensesBuilder();
final TrialLicensesBuilder trialLicensesBuilder = TrialLicensesBuilder.trialLicensesBuilder();
String fieldName = null;
Set<String> encodedTrialLicenses = new HashSet<>();
Set<String> signatures = new HashSet<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
fieldName = parser.currentName();
@ -172,17 +109,18 @@ public class LicensesMetaData implements MetaData.Custom {
if (fieldName != null) {
if (fieldName.equals(Fields.LICENSES)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
licensesBuilder.license(licenseFromMap(parser.map()));
signatures.add(parser.text());
}
}
if (fieldName.equals(Fields.TRIAL_LICENSES)) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
trialLicensesBuilder.license(trialLicenseFromMap(parser.map()));
encodedTrialLicenses.add(parser.text());
}
}
}
}
return new LicensesMetaData(licensesBuilder.build(), trialLicensesBuilder.build());
return new LicensesMetaData(fromSignatures(signatures), fromEncodedTrialLicenses(encodedTrialLicenses));
}
/**
@ -191,17 +129,8 @@ public class LicensesMetaData implements MetaData.Custom {
@Override
public void toXContent(LicensesMetaData licensesMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.startObject();
builder.startArray(Fields.LICENSES);
for (ESLicense license : licensesMetaData.getLicenses()) {
builder.map(licenseAsMap(license));
}
builder.endArray();
builder.startArray(Fields.TRIAL_LICENSES);
for (TrialLicense license : licensesMetaData.getTrialLicenses()) {
builder.map(trialLicenseAsMap(license));
}
builder.endArray();
builder.array(Fields.LICENSES, toSignatures(licensesMetaData.getLicenses()));
builder.array(Fields.TRIAL_LICENSES, toEncodedTrialLicenses(licensesMetaData.getTrialLicenses()));
builder.endObject();
}

View File

@ -14,7 +14,6 @@ import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Provides;
import org.elasticsearch.common.inject.Singleton;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.ESLicenses;
@ -38,7 +37,7 @@ import static org.elasticsearch.license.plugin.core.TrialLicensesBuilder.EMPTY;
* - interface with LicenseManager
*/
@Singleton
public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ClusterStateListener, LicensesManagerService, LicensesValidatorService {
public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ClusterStateListener, LicensesManagerService, LicensesClientService {
private ESLicenseManager esLicenseManager;
@ -50,6 +49,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
public LicensesService(Settings settings, ClusterService clusterService) {
super(settings);
this.clusterService = clusterService;
this.esLicenseManager = ESLicenseManager.createClusterStateBasedInstance(clusterService);
}
/**
@ -109,7 +109,6 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
if (currentLicenses != null) {
//TODO: proper delete for trial licenses
final ESLicenses newLicenses = LicenseBuilders.removeFeatures(currentLicenses.getLicenses(), featuresToDelete);
currentLicenses = new LicensesMetaData(newLicenses, currentLicenses.getTrialLicenses());
}
@ -132,19 +131,24 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
MetaData metaData = currentState.metaData();
MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData());
LicensesMetaData currentLicenses = metaData.custom(LicensesMetaData.TYPE);
TrialLicensesBuilder newTrialLicenses = TrialLicensesBuilder.trialLicensesBuilder().license(trialLicense);
TrialLicensesBuilder trialLicensesBuilder = TrialLicensesBuilder.trialLicensesBuilder().license(trialLicense);
if (currentLicenses != null) {
if (currentLicenses.getTrialLicenses() != null) {
// had previous trial licenses
newTrialLicenses = newTrialLicenses.licenses(currentLicenses.getTrialLicenses());
currentLicenses = new LicensesMetaData(currentLicenses.getLicenses(), newTrialLicenses.build());
if (trialLicenseCheck(trialLicense.feature().string())) {
trialLicensesBuilder = trialLicensesBuilder.licenses(currentLicenses.getTrialLicenses());
currentLicenses = new LicensesMetaData(currentLicenses.getLicenses(), trialLicensesBuilder.build());
} else {
// had previously generated trial license for the feature
currentLicenses = new LicensesMetaData(currentLicenses.getLicenses(), currentLicenses.getTrialLicenses());
}
} else {
// had no previous trial license
currentLicenses = new LicensesMetaData(currentLicenses.getLicenses(), newTrialLicenses.build());
currentLicenses = new LicensesMetaData(currentLicenses.getLicenses(), trialLicensesBuilder.build());
}
} else {
// had no license meta data
currentLicenses = new LicensesMetaData(null, newTrialLicenses.build());
currentLicenses = new LicensesMetaData(null, trialLicensesBuilder.build());
}
trialLicenses = currentLicenses.getTrialLicenses();
mdBuilder.putCustom(LicensesMetaData.TYPE, currentLicenses);
@ -155,12 +159,16 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
public void onFailure(String source, @Nullable Throwable t) {
}
private boolean trialLicenseCheck(String feature) {
final TrialLicense license = trialLicenses.getTrialLicense(FeatureType.fromString(feature));
return license == null;
}
});
}
@Override
protected void doStart() throws ElasticsearchException {
esLicenseManager = ESLicenseManager.createClusterStateBasedInstance(clusterService);
if ( DiscoveryNode.dataNode(settings) || DiscoveryNode.masterNode(settings)) {
clusterService.add(this);
}
@ -189,6 +197,19 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
}
@Override
public void registerAndActivate(String feature, TrialLicenseOptions trialLicenseOptions, Listener listener) {
// check if one-time trial license has been generated for this feature
// if not call registerTrialLicense()
// if trial license generated, onEnabled should return
// else check actual licenses
TrialLicense trialLicense = generateTrialLicense(feature, trialLicenseOptions.durationInDays, trialLicenseOptions.maxNodes);
registerTrialLicense(trialLicense);
}
public boolean checkLicenseExpiry(String feature) {
//TODO make validation cluster state aware
//check trial license existence
@ -201,12 +222,6 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
return esLicenseManager.hasLicenseForFeature(FeatureType.fromString(feature));
}
@Override
public boolean checkMaxNode(String feature) {
//TODO make validation cluster state aware
return false;
}
private static Set<FeatureType> asFeatureTypes(Set<String> featureTypeStrings) {
Set<FeatureType> featureTypes = new HashSet<>(featureTypeStrings.size());
for (String featureString : featureTypeStrings) {
@ -237,10 +252,22 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
private TrialLicense generateTrialLicense(String feature, int durationInDays, int maxNodes) {
return TrialLicensesBuilder.trialLicenseBuilder()
.issuedTo(clusterService.state().getClusterName().value())
.issueDate(System.currentTimeMillis())
.durationInDays(durationInDays)
.feature(FeatureType.fromString(feature))
.maxNodes(maxNodes)
.build();
}
public static class TrialLicenseOptions {
final int durationInDays;
final int maxNodes;
public TrialLicenseOptions(int durationInDays, int maxNodes) {
this.durationInDays = durationInDays;
this.maxNodes = maxNodes;
}
}
}

View File

@ -1,14 +0,0 @@
/*
* 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.core;
public interface LicensesValidatorService {
public boolean checkLicenseExpiry(String feature);
public boolean checkMaxNode(String feature);
}

View File

@ -17,6 +17,8 @@ public interface TrialLicenses extends Iterable<TrialLicenses.TrialLicense> {
public interface TrialLicense {
public String issuedTo();
public FeatureType feature();
public long issueDate();

View File

@ -5,10 +5,13 @@
*/
package org.elasticsearch.license.plugin.core;
import org.apache.commons.codec.binary.Base64;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.license.core.DateUtils;
import org.elasticsearch.license.core.ESLicenses;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.*;
import static org.elasticsearch.license.plugin.core.TrialLicenses.TrialLicense;
@ -25,6 +28,67 @@ public class TrialLicensesBuilder {
return new TrialLicenseBuilder();
}
public static TrialLicense fromEncodedTrialLicense(String encodedTrialLicense) {
byte[] encodedBytes = Base64.decodeBase64(encodedTrialLicense);
ByteBuffer byteBuffer = ByteBuffer.wrap(encodedBytes);
int uidLen = byteBuffer.getInt();
byte[] uidBytes = new byte[uidLen];
byteBuffer.get(uidBytes);
String uid = new String(uidBytes, Charset.forName("UTF-8"));
int issuedToLen = byteBuffer.getInt();
byte[] issuedToBytes = new byte[issuedToLen];
byteBuffer.get(issuedToBytes);
String issuedTo = new String(issuedToBytes, Charset.forName("UTF-8"));
int featureLen = byteBuffer.getInt();
byte[] featureBytes = new byte[featureLen];
byteBuffer.get(featureBytes);
String feature = new String(featureBytes, Charset.forName("UTF-8"));
int maxNodes = byteBuffer.getInt();
long issueDate = byteBuffer.getLong();
long expiryDate = byteBuffer.getLong();
return trialLicenseBuilder()
.uid(uid)
.issuedTo(issuedTo)
.feature(ESLicenses.FeatureType.fromString(feature))
.maxNodes(maxNodes)
.issueDate(issueDate)
.expiryDate(expiryDate)
.build();
}
public static String toEncodedTrialLicense(TrialLicense trialLicense) {
byte[] uidBytes = trialLicense.uid().getBytes(Charset.forName("UTF-8"));
String feature = trialLicense.feature().string();
byte[] featureBytes = feature.getBytes(Charset.forName("UTF-8"));
byte[] issuedToBytes = trialLicense.issuedTo().getBytes(Charset.forName("UTF-8"));
// uid len + uid bytes + issuedTo len + issuedTo bytes + feature bytes length + feature bytes + maxNodes + issueDate + expiryDate
int len = 4 + uidBytes.length + issuedToBytes.length + featureBytes.length + 4 + 8 + 8;
final byte[] encodedLicense = new byte[len];
ByteBuffer byteBuffer = ByteBuffer.wrap(encodedLicense);
byteBuffer.putInt(uidBytes.length);
byteBuffer.put(uidBytes);
byteBuffer.putInt(issuedToBytes.length);
byteBuffer.put(issuedToBytes);
byteBuffer.putInt(featureBytes.length);
byteBuffer.put(featureBytes);
byteBuffer.putInt(trialLicense.maxNodes());
byteBuffer.putLong(trialLicense.issueDate());
byteBuffer.putLong(trialLicense.expiryDate());
return Base64.encodeBase64String(encodedLicense);
}
public static TrialLicenses merge(TrialLicenses trialLicenses, TrialLicenses mergeTrialLicenses) {
if (trialLicenses == null && mergeTrialLicenses == null) {
throw new IllegalArgumentException("both licenses can not be null");
@ -90,6 +154,7 @@ public class TrialLicensesBuilder {
private int durationInDays = -1;
private int maxNodes = -1;
private String uid = null;
private String issuedTo;
public TrialLicenseBuilder() {
}
@ -99,6 +164,11 @@ public class TrialLicensesBuilder {
return this;
}
public TrialLicenseBuilder issuedTo(String issuedTo) {
this.issuedTo = issuedTo;
return this;
}
public TrialLicenseBuilder maxNodes(int maxNodes) {
this.maxNodes = maxNodes;
return this;
@ -134,6 +204,12 @@ public class TrialLicensesBuilder {
uid = UUID.randomUUID().toString();
}
return new TrialLicense() {
@Override
public String issuedTo() {
return issuedTo;
}
@Override
public ESLicenses.FeatureType feature() {
return featureType;
@ -163,7 +239,9 @@ public class TrialLicensesBuilder {
private void verify() {
String msg = null;
if (featureType == null) {
if (issuedTo == null) {
msg = "issuedTo has to be set";
} else if (featureType == null) {
msg = "feature has to be set";
} else if (issueDate == -1) {
msg = "issueDate has to be set";

View File

@ -30,7 +30,7 @@ public class RestDeleteLicenseAction extends BaseRestHandler {
@Inject
public RestDeleteLicenseAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client);
controller.registerHandler(DELETE, "/_cluster/license/{features}", this);
controller.registerHandler(DELETE, "/licenses/{features}", this);
}

View File

@ -13,10 +13,12 @@ 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.license.plugin.core.TrialLicenses;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import static org.elasticsearch.license.plugin.action.Utils.licenseAsMap;
import static org.elasticsearch.license.plugin.action.Utils.trialLicenseAsMap;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.OK;
@ -25,19 +27,22 @@ public class RestGetLicenseAction extends BaseRestHandler {
@Inject
public RestGetLicenseAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client);
controller.registerHandler(GET, "/_cluster/license", this);
controller.registerHandler(GET, "/licenses", this);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) {
client.admin().cluster().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(), new RestBuilderListener<GetLicenseResponse>(channel) {
@Override
public RestResponse buildResponse(GetLicenseResponse getLicenseResponse, XContentBuilder builder) throws Exception {
public RestResponse buildResponse(GetLicenseResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
builder.startArray("licenses");
for (ESLicenses.ESLicense license : getLicenseResponse.licenses()) {
for (ESLicenses.ESLicense license : response.licenses()) {
builder.map(licenseAsMap(license));
}
for (TrialLicenses.TrialLicense trialLicense : response.trialLicenses()) {
builder.map(trialLicenseAsMap(trialLicense));
}
builder.endArray();
builder.endObject();
return new BytesRestResponse(OK, builder);

View File

@ -25,8 +25,8 @@ public class RestPutLicenseAction extends BaseRestHandler {
@Inject
public RestPutLicenseAction(Settings settings, RestController controller, Client client) {
super(settings, controller, client);
controller.registerHandler(PUT, "/_cluster/license", this);
controller.registerHandler(POST, "/_cluster/license", this);
controller.registerHandler(PUT, "/licenses", this);
controller.registerHandler(POST, "/licenses", this);
}