metaData fixes; Initial licneseClientService; trial license encoding/decoding
Original commit: elastic/x-pack-elasticsearch@6913a4dc23
This commit is contained in:
parent
a8f5f0151d
commit
52d29f4fbb
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -17,6 +17,8 @@ public interface TrialLicenses extends Iterable<TrialLicenses.TrialLicense> {
|
|||
|
||||
public interface TrialLicense {
|
||||
|
||||
public String issuedTo();
|
||||
|
||||
public FeatureType feature();
|
||||
|
||||
public long issueDate();
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue