[marvel] Integrated the new unified license model

- Added the notion of `Licensee.Status` (holds both the `License.OperationMode` and the `LicenseState`)
- Added a support base class for all `Licensee` implementations. The idea behind this is that implementations will centralized the licensing logic in one class (same as `MarvelLicensee` does), but if there's a requirement for more "proactiveness" on license status change, different components can register a `Licensee.Listener` to be notified on license changes.
- Since we introduced `License.OperationMode` as part of the license refactoring, there's no need anymore for Marvel's `Mode` enum.

Closes elastic/elasticsearch#690

Original commit: elastic/x-pack-elasticsearch@8a66bc163f
This commit is contained in:
uboness 2015-10-09 12:56:54 +02:00
parent 59ac529e8b
commit f6a613fa88
28 changed files with 158 additions and 362 deletions

View File

@ -21,7 +21,7 @@ import org.elasticsearch.marvel.agent.renderer.RendererModule;
import org.elasticsearch.marvel.agent.settings.MarvelModule;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseModule;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.MarvelInternalUserHolder;
import org.elasticsearch.marvel.shield.MarvelShieldIntegration;
import org.elasticsearch.marvel.shield.MarvelShieldModule;
@ -82,7 +82,7 @@ public class MarvelPlugin extends Plugin {
if (!enabled) {
return Collections.emptyList();
}
return Arrays.<Class<? extends LifecycleComponent>>asList(LicenseService.class, AgentService.class);
return Arrays.<Class<? extends LifecycleComponent>>asList(MarvelLicensee.class, AgentService.class);
}
public static boolean marvelEnabled(Settings settings) {

View File

@ -20,7 +20,6 @@ import org.elasticsearch.marvel.agent.exporter.Exporter;
import org.elasticsearch.marvel.agent.exporter.Exporters;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.node.settings.NodeSettingsService;
import java.util.*;
@ -39,8 +38,7 @@ public class AgentService extends AbstractLifecycleComponent<AgentService> imple
@Inject
public AgentService(Settings settings, NodeSettingsService nodeSettingsService,
LicenseService licenseService, MarvelSettings marvelSettings,
Set<Collector> collectors, Exporters exporters) {
MarvelSettings marvelSettings, Set<Collector> collectors, Exporters exporters) {
super(settings);
this.marvelSettings = marvelSettings;
this.samplingInterval = marvelSettings.interval().millis();
@ -49,7 +47,6 @@ public class AgentService extends AbstractLifecycleComponent<AgentService> imple
this.exporters = exporters;
nodeSettingsService.addListener(this);
logger.trace("marvel is running in [{}] mode", licenseService.mode());
}
protected Set<Collector> filterCollectors(Set<Collector> collectors, String[] filters) {

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import java.util.Collection;
@ -23,15 +23,15 @@ public abstract class AbstractCollector<T> extends AbstractLifecycleComponent<T>
protected final ClusterService clusterService;
protected final MarvelSettings marvelSettings;
protected final LicenseService licenseService;
protected final MarvelLicensee licensee;
@Inject
public AbstractCollector(Settings settings, String name, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService) {
public AbstractCollector(Settings settings, String name, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee licensee) {
super(settings);
this.name = name;
this.clusterService = clusterService;
this.marvelSettings = marvelSettings;
this.licenseService = licenseService;
this.licensee = licensee;
}
@Override
@ -58,11 +58,11 @@ public abstract class AbstractCollector<T> extends AbstractLifecycleComponent<T>
* Indicates if the current collector is allowed to collect data
*/
protected boolean shouldCollect() {
boolean validLicense = licenseService.enabled() || licenseService.inExpirationGracePeriod();
if (!validLicense) {
if (licensee.collectionEnabled()) {
logger.trace("collector [{}] can not collect data due to invalid license", name());
return false;
}
return validLicense;
return true;
}
protected boolean isLocalNodeMaster() {

View File

@ -16,7 +16,7 @@ import org.elasticsearch.license.core.License;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.SecuredClient;
import java.util.ArrayList;
@ -37,15 +37,15 @@ public class ClusterInfoCollector extends AbstractCollector<ClusterInfoMarvelDoc
public static final String TYPE = "cluster_info";
private final ClusterName clusterName;
private final LicenseService licenseService;
private final MarvelLicensee marvelLicensee;
private final Client client;
@Inject
public ClusterInfoCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public ClusterInfoCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
ClusterName clusterName, SecuredClient client) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.clusterName = clusterName;
this.licenseService = licenseService;
this.marvelLicensee = marvelLicensee;
this.client = client;
}
@ -59,16 +59,14 @@ public class ClusterInfoCollector extends AbstractCollector<ClusterInfoMarvelDoc
protected Collection<MarvelDoc> doCollect() throws Exception {
List<MarvelDoc> results = new ArrayList<>(1);
// Retrieves all licenses
// TODO: we should only work with one license
List<License> licenses = Collections.singletonList(licenseService.license());
License license = marvelLicensee.getLicense();
// Retrieves additional cluster stats
ClusterStatsResponse clusterStats = client.admin().cluster().prepareClusterStats().get(marvelSettings.clusterStatsTimeout());
String clusterUUID = clusterUUID();
results.add(new ClusterInfoMarvelDoc(MarvelSettings.MARVEL_DATA_INDEX_NAME, TYPE, clusterUUID, clusterUUID, System.currentTimeMillis(),
clusterName.value(), Version.CURRENT.toString(), licenses, clusterStats));
clusterName.value(), Version.CURRENT.toString(), license, clusterStats));
return Collections.unmodifiableCollection(results);
}
}

View File

@ -9,21 +9,19 @@ import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.license.core.License;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import java.util.List;
public class ClusterInfoMarvelDoc extends MarvelDoc {
private final String clusterName;
private final String version;
private final List<License> licenses;
private final License license;
private final ClusterStatsResponse clusterStats;
ClusterInfoMarvelDoc(String index, String type, String id, String clusterUUID, long timestamp,
String clusterName, String version, List<License> licenses, ClusterStatsResponse clusterStats) {
String clusterName, String version, License license, ClusterStatsResponse clusterStats) {
super(index, type, id, clusterUUID, timestamp);
this.clusterName = clusterName;
this.version = version;
this.licenses = licenses;
this.license = license;
this.clusterStats = clusterStats;
}
@ -35,8 +33,8 @@ public class ClusterInfoMarvelDoc extends MarvelDoc {
return version;
}
public List<License> getLicenses() {
return licenses;
public License getLicense() {
return license;
}
public ClusterStatsResponse getClusterStats() {

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.SecuredClient;
import java.util.ArrayList;
@ -36,9 +36,9 @@ public class ClusterStateCollector extends AbstractCollector<ClusterStateCollect
private final Client client;
@Inject
public ClusterStateCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public ClusterStateCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
SecuredClient client) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.client = client;
}

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.SecuredClient;
import java.util.ArrayList;
@ -35,9 +35,9 @@ public class ClusterStatsCollector extends AbstractCollector<ClusterStatsCollect
private final Client client;
@Inject
public ClusterStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public ClusterStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
SecuredClient client) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.client = client;
}

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.SecuredClient;
import java.util.ArrayList;
@ -36,9 +36,9 @@ public class IndexRecoveryCollector extends AbstractCollector<IndexRecoveryColle
private final Client client;
@Inject
public IndexRecoveryCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public IndexRecoveryCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
SecuredClient client) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.client = client;
}

View File

@ -15,7 +15,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.SecuredClient;
import java.util.ArrayList;
@ -37,9 +37,9 @@ public class IndexStatsCollector extends AbstractCollector<IndexStatsCollector>
private final Client client;
@Inject
public IndexStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public IndexStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
SecuredClient client) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.client = client;
}

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.marvel.shield.SecuredClient;
import java.util.Collection;
@ -32,9 +32,9 @@ public class IndicesStatsCollector extends AbstractCollector<IndicesStatsCollect
private final Client client;
@Inject
public IndicesStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public IndicesStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
SecuredClient client) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.client = client;
}

View File

@ -20,7 +20,7 @@ import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.node.service.NodeService;
import java.util.ArrayList;
@ -48,10 +48,10 @@ public class NodeStatsCollector extends AbstractCollector<NodeStatsCollector> {
private final Provider<DiskThresholdDecider> diskThresholdDeciderProvider;
@Inject
public NodeStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService,
public NodeStatsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee,
NodeService nodeService, DiscoveryService discoveryService, NodeEnvironment nodeEnvironment,
Provider<DiskThresholdDecider> diskThresholdDeciderProvider) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
this.nodeService = nodeService;
this.discoveryService = discoveryService;
this.nodeEnvironment = nodeEnvironment;

View File

@ -16,7 +16,7 @@ import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.marvel.agent.collector.AbstractCollector;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import java.util.ArrayList;
import java.util.Collection;
@ -35,8 +35,8 @@ public class ShardsCollector extends AbstractCollector<ShardsCollector> {
public static final String TYPE = "shards";
@Inject
public ShardsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, LicenseService licenseService) {
super(settings, NAME, clusterService, marvelSettings, licenseService);
public ShardsCollector(Settings settings, ClusterService clusterService, MarvelSettings marvelSettings, MarvelLicensee marvelLicensee) {
super(settings, NAME, clusterService, marvelSettings, marvelLicensee);
}
@Override

View File

@ -6,6 +6,7 @@
package org.elasticsearch.marvel.agent.renderer.cluster;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.hash.MessageDigests;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -16,7 +17,7 @@ import org.elasticsearch.marvel.agent.renderer.AbstractRenderer;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
public class ClusterInfoRenderer extends AbstractRenderer<ClusterInfoMarvelDoc> {
public ClusterInfoRenderer() {
@ -28,25 +29,17 @@ public class ClusterInfoRenderer extends AbstractRenderer<ClusterInfoMarvelDoc>
builder.field(Fields.CLUSTER_NAME, marvelDoc.getClusterName());
builder.field(Fields.VERSION, marvelDoc.getVersion());
builder.startArray(Fields.LICENSES);
List<License> licenses = marvelDoc.getLicenses();
if (licenses != null) {
for (License license : licenses) {
builder.startObject();
builder.field(Fields.STATUS, license.status().label());
builder.field(Fields.UID, license.uid());
builder.field(Fields.TYPE, license.type());
builder.dateValueField(Fields.ISSUE_DATE_IN_MILLIS, Fields.ISSUE_DATE, license.issueDate());
builder.dateValueField(Fields.EXPIRY_DATE_IN_MILLIS, Fields.EXPIRY_DATE, license.expiryDate());
builder.field(Fields.MAX_NODES, license.maxNodes());
builder.field(Fields.ISSUED_TO, license.issuedTo());
builder.field(Fields.ISSUER, license.issuer());
builder.field(Fields.HKEY, hash(license, marvelDoc.clusterUUID()));
builder.endObject();
}
License license = marvelDoc.getLicense();
if (license != null) {
builder.startObject(Fields.LICENSE);
Map<String, String> extraParams = new MapBuilder<String, String>()
.put(License.REST_VIEW_MODE, "true")
.map();
params = new ToXContent.DelegatingMapParams(extraParams, params);
license.toInnerXContent(builder, params);
builder.field(Fields.HKEY, hash(license, marvelDoc.clusterUUID()));
builder.endObject();
}
builder.endArray();
builder.startObject(Fields.CLUSTER_STATS);
ClusterStatsResponse clusterStats = marvelDoc.getClusterStats();
@ -67,21 +60,13 @@ public class ClusterInfoRenderer extends AbstractRenderer<ClusterInfoMarvelDoc>
static final class Fields {
static final XContentBuilderString CLUSTER_NAME = new XContentBuilderString("cluster_name");
static final XContentBuilderString LICENSES = new XContentBuilderString("licenses");
static final XContentBuilderString LICENSE = new XContentBuilderString("license");
static final XContentBuilderString VERSION = new XContentBuilderString("version");
static final XContentBuilderString CLUSTER_STATS = new XContentBuilderString("cluster_stats");
static final XContentBuilderString HKEY = new XContentBuilderString("hkey");
static final XContentBuilderString STATUS = new XContentBuilderString("status");
static final XContentBuilderString UID = new XContentBuilderString("uid");
static final XContentBuilderString TYPE = new XContentBuilderString("type");
static final XContentBuilderString ISSUE_DATE_IN_MILLIS = new XContentBuilderString("issue_date_in_millis");
static final XContentBuilderString ISSUE_DATE = new XContentBuilderString("issue_date");
static final XContentBuilderString EXPIRY_DATE_IN_MILLIS = new XContentBuilderString("expiry_date_in_millis");
static final XContentBuilderString EXPIRY_DATE = new XContentBuilderString("expiry_date");
static final XContentBuilderString MAX_NODES = new XContentBuilderString("max_nodes");
static final XContentBuilderString ISSUED_TO = new XContentBuilderString("issued_to");
static final XContentBuilderString ISSUER = new XContentBuilderString("issuer");
}
}

View File

@ -39,9 +39,8 @@ public class MarvelSettings extends AbstractComponent implements NodeSettingsSer
public static final String INDEX_RECOVERY_TIMEOUT = PREFIX + "index.recovery.timeout";
public static final String INDEX_RECOVERY_ACTIVE_ONLY = PREFIX + "index.recovery.active_only";
public static final String COLLECTORS = PREFIX + "collectors";
public static final String LICENSE_GRACE_PERIOD = PREFIX + "license.grace.period";
private Map<String, ? extends MarvelSetting> settings = Collections.EMPTY_MAP;
private Map<String, ? extends MarvelSetting> settings = Collections.emptyMap();
@Inject
public MarvelSettings(Settings clusterSettings, NodeSettingsService nodeSettingsService) {
@ -79,8 +78,6 @@ public class MarvelSettings extends AbstractComponent implements NodeSettingsSer
"Flag to indicate if only active recoveries should be collected (default to false: all recoveries are collected)"));
map.put(COLLECTORS, arraySetting(COLLECTORS, Strings.EMPTY_ARRAY,
"List of collectors allowed to collect data (default to all)"));
map.put(LICENSE_GRACE_PERIOD, timeSetting(LICENSE_GRACE_PERIOD, MAX_LICENSE_GRACE_PERIOD,
"Period during which the agent continues to collect data even if the license is expired (default to 7 days, cannot be greater than 7 days)"));
return Collections.unmodifiableMap(map);
}
@ -185,11 +182,4 @@ public class MarvelSettings extends AbstractComponent implements NodeSettingsSer
return getSettingValue(COLLECTORS);
}
public TimeValue licenseExpirationGracePeriod() {
TimeValue delay = getSettingValue(LICENSE_GRACE_PERIOD);
if ((delay.millis() >= 0) && (delay.millis() < MAX_LICENSE_GRACE_PERIOD.millis())) {
return delay;
}
return MAX_LICENSE_GRACE_PERIOD;
}
}

View File

@ -15,7 +15,7 @@ public class LicenseModule extends AbstractModule {
@Override
protected void configure() {
bind(LicenseService.class).asEagerSingleton();
bind(MarvelLicensee.class).asEagerSingleton();
}
private void verifyLicensePlugin() {

View File

@ -1,149 +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.marvel.license;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.support.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.marvel.MarvelPlugin;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.mode.Mode;
public class LicenseService extends AbstractLifecycleComponent<LicenseService> implements Licensee {
public static final String FEATURE_NAME = MarvelPlugin.NAME;
private final LicensesManagerService managerService;
private final LicenseeRegistry clientService;
private final MarvelSettings marvelSettings;
private volatile Mode mode;
private volatile LicenseState state;
private volatile long expiryDate;
@Inject
public LicenseService(Settings settings, LicenseeRegistry clientService, LicensesManagerService managerService, MarvelSettings marvelSettings) {
super(settings);
this.managerService = managerService;
this.clientService = clientService;
this.marvelSettings = marvelSettings;
this.mode = Mode.LITE;
}
@Override
protected void doStart() throws ElasticsearchException {
clientService.register(this);
}
@Override
protected void doStop() throws ElasticsearchException {
}
@Override
protected void doClose() throws ElasticsearchException {
}
/**
* @return the current marvel's operating mode
*/
public Mode mode() {
return mode;
}
/**
* @return all registered licenses
*/
public License license() {
return managerService.getLicense();
}
/**
* @return true if the marvel license is enabled
*/
public boolean enabled() {
return state == LicenseState.ENABLED || state == LicenseState.GRACE_PERIOD;
}
/**
* TODO: remove licensing grace period, just check for state == LicensesClientService.LicenseState.GRACE_PERIOD instead
*
* @return true if marvel is running within the "grace period", ie when the license
* is expired but a given extra delay is not yet elapsed
*/
public boolean inExpirationGracePeriod() {
return System.currentTimeMillis() <= (expiryDate() + marvelSettings.licenseExpirationGracePeriod().millis());
}
/**
* @return the license's expiration date (as a long)
*/
public long expiryDate() {
return expiryDate;
}
@Override
public String id() {
return FEATURE_NAME;
}
@Override
public String[] expirationMessages() {
// TODO add messages to be logged around license expiry
return Strings.EMPTY_ARRAY;
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
case BASIC:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case GOLD:
case PLATINUM:
return new String[] {
LoggerMessageFormat.format(
"Multi-cluster support is disabled for clusters with [{}] licenses.\n" +
"If you are running multiple customers, users won't be able to access this\n" +
"all the clusters with [{}] licenses from a single Marvel instance. To access them\n" +
"a dedicated and separated marvel instance will be required for each cluster",
newLicense.type(), newLicense.type())
};
}
}
}
return Strings.EMPTY_ARRAY;
}
@Override
public void onChange(License license, LicenseState state) {
synchronized (this) {
this.state = state;
if (license != null) {
try {
mode = Mode.fromName(license.type());
} catch (IllegalArgumentException e) {
mode = Mode.LITE;
}
expiryDate = license.expiryDate();
} else {
mode = Mode.LITE;
}
if (state == LicenseState.DISABLED) {
mode = Mode.LITE;
}
}
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.marvel.license;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.support.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.core.License;
import org.elasticsearch.license.plugin.core.*;
import org.elasticsearch.marvel.MarvelPlugin;
public class MarvelLicensee extends AbstractLicenseeComponent<MarvelLicensee> implements Licensee {
@Inject
public MarvelLicensee(Settings settings, LicenseeRegistry clientService, LicensesManagerService managerService) {
super(settings, MarvelPlugin.NAME, clientService, managerService);
}
@Override
public String[] expirationMessages() {
return new String[] {
"The agent will stop collecting cluster and indices metrics"
};
}
@Override
public String[] acknowledgmentMessages(License currentLicense, License newLicense) {
switch (newLicense.operationMode()) {
case BASIC:
if (currentLicense != null) {
switch (currentLicense.operationMode()) {
case TRIAL:
case GOLD:
case PLATINUM:
return new String[] {
LoggerMessageFormat.format(
"Multi-cluster support is disabled for clusters with [{}] license. If you are\n" +
"running multiple clusters, users won't be able to access the clusters with\n" +
"[{}] licenses from within a single Marvel instance. You will have to deploy a\n" +
"separate and dedicated Marvel instance for each [{}] cluster you wish to monitor.",
newLicense.type(), newLicense.type(), newLicense.type())
};
}
}
}
return Strings.EMPTY_ARRAY;
}
public boolean collectionEnabled() {
return status.getMode() != License.OperationMode.NONE &&
status.getLicenseState() != LicenseState.DISABLED;
}
}

View File

@ -1,71 +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.marvel.mode;
import org.elasticsearch.ElasticsearchException;
import java.util.Locale;
/**
* Marvel's operating mode
*/
public enum Mode {
/**
* Marvel runs in downgraded mode
*
* TODO: do we really need mode?
*/
TRIAL(0),
/**
* Marvel runs in downgraded mode
*/
LITE(0),
/**
* Marvel runs in normal mode
*/
STANDARD(1);
private final byte id;
Mode(int id) {
this.id = (byte) id;
}
public byte getId() {
return id;
}
public static Mode fromId(byte id) {
switch (id) {
case 0:
return TRIAL;
case 1:
return LITE;
case 2:
return STANDARD;
case 3:
default:
throw new ElasticsearchException("unknown marvel mode id [" + id + "]");
}
}
public static Mode fromName(String name) {
switch (name.toLowerCase(Locale.ROOT)) {
case "trial":
return LITE;
case "basic":
case "gold" :
case "silver":
case "platinum":
return STANDARD;
default:
throw new ElasticsearchException("unknown marvel mode name [" + name + "]");
}
}
}

View File

@ -11,7 +11,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.junit.Test;
import java.util.Collection;
@ -40,8 +40,7 @@ public class ClusterInfoCollectorTests extends AbstractCollectorTestCase {
assertThat(clusterInfoMarvelDoc.getClusterName(), equalTo(client().admin().cluster().prepareState().setMetaData(true).get().getClusterName().value()));
assertThat(clusterInfoMarvelDoc.getVersion(), equalTo(client().admin().cluster().prepareNodesInfo().get().getNodes()[0].getVersion().toString()));
assertNotNull(clusterInfoMarvelDoc.getLicenses());
assertThat(clusterInfoMarvelDoc.getLicenses(), hasSize(isInternalCluster() && shieldEnabled ? 2 : 1));
assertThat(clusterInfoMarvelDoc.getLicense(), notNullValue());
assertNotNull(clusterInfoMarvelDoc.getClusterStats());
assertThat(clusterInfoMarvelDoc.getClusterStats().getNodesStats().getCounts().getTotal(), equalTo(internalCluster().getNodeNames().length));
@ -99,7 +98,7 @@ public class ClusterInfoCollectorTests extends AbstractCollectorTestCase {
return new ClusterInfoCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId),
internalCluster().getInstance(MarvelLicensee.class, nodeId),
internalCluster().getInstance(ClusterName.class, nodeId),
securedClient(nodeId));
}

View File

@ -12,7 +12,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.junit.Test;
import java.util.Collection;
@ -163,7 +163,7 @@ public class ClusterStateCollectorTests extends AbstractCollectorTestCase {
return new ClusterStateCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId),
internalCluster().getInstance(MarvelLicensee.class, nodeId),
securedClient(nodeId));
}
}

View File

@ -10,7 +10,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.junit.Test;
import java.util.Collection;
@ -81,7 +81,7 @@ public class ClusterStatsCollectorTests extends AbstractCollectorTestCase {
return new ClusterStatsCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId),
internalCluster().getInstance(MarvelLicensee.class, nodeId),
securedClient(nodeId));
}
}

View File

@ -13,7 +13,7 @@ import org.elasticsearch.indices.recovery.RecoveryState;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.junit.Test;
@ -157,7 +157,7 @@ public class IndexRecoveryCollectorTests extends AbstractCollectorTestCase {
return new IndexRecoveryCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId),
internalCluster().getInstance(MarvelLicensee.class, nodeId),
securedClient(nodeId));
}
}

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Test;
@ -215,7 +215,7 @@ public class IndexStatsCollectorTests extends AbstractCollectorTestCase {
return new IndexStatsCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId),
internalCluster().getInstance(MarvelLicensee.class, nodeId),
securedClient(nodeId));
}
}

View File

@ -15,7 +15,7 @@ import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.elasticsearch.node.service.NodeService;
import org.junit.Test;
@ -82,7 +82,7 @@ public class NodeStatsCollectorTests extends AbstractCollectorTestCase {
return new NodeStatsCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId),
internalCluster().getInstance(MarvelLicensee.class, nodeId),
internalCluster().getInstance(NodeService.class, nodeId),
internalCluster().getInstance(DiscoveryService.class, nodeId),
internalCluster().getInstance(NodeEnvironment.class, nodeId),

View File

@ -13,7 +13,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.marvel.agent.collector.AbstractCollectorTestCase;
import org.elasticsearch.marvel.agent.exporter.MarvelDoc;
import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.license.LicenseService;
import org.elasticsearch.marvel.license.MarvelLicensee;
import org.junit.Test;
import java.util.Collection;
@ -198,6 +198,6 @@ public class ShardsCollectorTests extends AbstractCollectorTestCase {
return new ShardsCollector(internalCluster().getInstance(Settings.class, nodeId),
internalCluster().getInstance(ClusterService.class, nodeId),
internalCluster().getInstance(MarvelSettings.class, nodeId),
internalCluster().getInstance(LicenseService.class, nodeId));
internalCluster().getInstance(MarvelLicensee.class, nodeId));
}
}

View File

@ -16,7 +16,6 @@ import org.elasticsearch.marvel.agent.settings.MarvelSettings;
import org.elasticsearch.marvel.test.MarvelIntegTestCase;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
@ -66,14 +65,10 @@ public class ClusterInfoIT extends MarvelIntegTestCase {
assertThat((String) source.get(ClusterInfoRenderer.Fields.CLUSTER_NAME.underscore().toString()), equalTo(cluster().getClusterName()));
assertThat((String) source.get(ClusterInfoRenderer.Fields.VERSION.underscore().toString()), equalTo(Version.CURRENT.toString()));
Object licensesList = source.get(ClusterInfoRenderer.Fields.LICENSES.underscore().toString());
assertThat(licensesList, instanceOf(List.class));
Object licenseObj = source.get(ClusterInfoRenderer.Fields.LICENSE.underscore().toString());
assertThat(licenseObj, instanceOf(Map.class));
Map license = (Map) licenseObj;
logger.warn("--> checking number of licenses [internal cluster:{}, shield enabled:{}]", isInternalCluster(), shieldEnabled);
List licenses = (List) licensesList;
assertThat(licenses.size(), equalTo(isInternalCluster() && shieldEnabled ? 2 : 1));
Map license = (Map) licenses.iterator().next();
assertThat(license, instanceOf(Map.class));
String uid = (String) license.get(ClusterInfoRenderer.Fields.UID.underscore().toString());
@ -82,10 +77,10 @@ public class ClusterInfoIT extends MarvelIntegTestCase {
String type = (String) license.get(ClusterInfoRenderer.Fields.TYPE.underscore().toString());
assertThat(type, not(isEmptyOrNullString()));
String status = (String) license.get(ClusterInfoRenderer.Fields.STATUS.underscore().toString());
String status = (String) license.get(License.XFields.STATUS.underscore().toString());
assertThat(status, not(isEmptyOrNullString()));
Long expiryDate = (Long) license.get(ClusterInfoRenderer.Fields.EXPIRY_DATE_IN_MILLIS.underscore().toString());
Long expiryDate = (Long) license.get(License.XFields.EXPIRY_DATE_IN_MILLIS.underscore().toString());
assertThat(expiryDate, greaterThan(0L));
// We basically recompute the hash here
@ -93,10 +88,10 @@ public class ClusterInfoIT extends MarvelIntegTestCase {
String recalculated = ClusterInfoRenderer.hash(status, uid, type, String.valueOf(expiryDate), clusterUUID);
assertThat(hkey, equalTo(recalculated));
assertThat((String) license.get(ClusterInfoRenderer.Fields.ISSUER.underscore().toString()), not(isEmptyOrNullString()));
assertThat((String) license.get(ClusterInfoRenderer.Fields.ISSUED_TO.underscore().toString()), not(isEmptyOrNullString()));
assertThat((Long) license.get(ClusterInfoRenderer.Fields.ISSUE_DATE_IN_MILLIS.underscore().toString()), greaterThan(0L));
assertThat((Integer) license.get(ClusterInfoRenderer.Fields.MAX_NODES.underscore().toString()), greaterThan(0));
assertThat((String) license.get(License.XFields.ISSUER.underscore().toString()), not(isEmptyOrNullString()));
assertThat((String) license.get(License.XFields.ISSUED_TO.underscore().toString()), not(isEmptyOrNullString()));
assertThat((Long) license.get(License.XFields.ISSUE_DATE_IN_MILLIS.underscore().toString()), greaterThan(0L));
assertThat((Integer) license.get(License.XFields.MAX_NODES.underscore().toString()), greaterThan(0));
Object clusterStats = source.get(ClusterStatsRenderer.Fields.CLUSTER_STATS.underscore().toString());
assertNotNull(clusterStats);
@ -109,9 +104,9 @@ public class ClusterInfoIT extends MarvelIntegTestCase {
.setIndices(MarvelSettings.MARVEL_DATA_INDEX_NAME)
.setTypes(ClusterInfoCollector.TYPE)
.setQuery(QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery(ClusterInfoRenderer.Fields.STATUS.underscore().toString(), License.Status.ACTIVE.label()))
.should(QueryBuilders.matchQuery(ClusterInfoRenderer.Fields.STATUS.underscore().toString(), License.Status.INVALID.label()))
.should(QueryBuilders.matchQuery(ClusterInfoRenderer.Fields.STATUS.underscore().toString(), License.Status.EXPIRED.label()))
.should(QueryBuilders.matchQuery(License.XFields.STATUS.underscore().toString(), License.Status.ACTIVE.label()))
.should(QueryBuilders.matchQuery(License.XFields.STATUS.underscore().toString(), License.Status.INVALID.label()))
.should(QueryBuilders.matchQuery(License.XFields.STATUS.underscore().toString(), License.Status.EXPIRED.label()))
.minimumNumberShouldMatch(1)
).get(), 0L);

View File

@ -14,7 +14,7 @@ import org.elasticsearch.test.ESIntegTestCase;
import org.junit.Test;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.equalTo;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 1)
public class MarvelSettingsTests extends MarvelIntegTestCase {
@ -50,7 +50,6 @@ public class MarvelSettingsTests extends MarvelIntegTestCase {
.put(MarvelSettings.INDEX_RECOVERY_TIMEOUT, recoveryTimeout)
.put(MarvelSettings.INDEX_RECOVERY_ACTIVE_ONLY, recoveryActiveOnly)
.putArray(MarvelSettings.COLLECTORS, collectors)
.put(MarvelSettings.LICENSE_GRACE_PERIOD, licenseGracePeriod)
.build();
}
@ -67,7 +66,6 @@ public class MarvelSettingsTests extends MarvelIntegTestCase {
assertThat(marvelSettings.recoveryTimeout().millis(), equalTo(recoveryTimeout.millis()));
assertThat(marvelSettings.recoveryActiveOnly(), equalTo(recoveryActiveOnly));
assertArrayEquals(marvelSettings.collectors(), collectors);
assertThat(marvelSettings.licenseExpirationGracePeriod().millis(), allOf(greaterThanOrEqualTo(0L), lessThanOrEqualTo(MarvelSettings.MAX_LICENSE_GRACE_PERIOD.millis())));
}
logger.info("--> testing marvel dynamic settings update");

View File

@ -17,18 +17,18 @@ import org.elasticsearch.license.plugin.core.LicenseState;
import org.elasticsearch.license.plugin.core.Licensee;
import org.elasticsearch.license.plugin.core.LicenseeRegistry;
import org.elasticsearch.marvel.MarvelPlugin;
import org.elasticsearch.marvel.mode.Mode;
import org.elasticsearch.marvel.test.MarvelIntegTestCase;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.junit.Test;
import java.util.*;
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
@ClusterScope(scope = SUITE, transportClientRatio = 0, numClientNodes = 0)
public class LicenseIntegrationTests extends MarvelIntegTestCase {
@ -50,25 +50,22 @@ public class LicenseIntegrationTests extends MarvelIntegTestCase {
@Test
public void testEnableDisableLicense() {
assertThat(getLicenseService().mode(), equalTo(Mode.STANDARD));
assertThat(getLicenseService().enabled(), is(true));
assertThat(getLicenseService().expiryDate(), greaterThan(0L));
assertThat(getLicensee().getStatus().getLicenseState(), isOneOf(LicenseState.ENABLED, LicenseState.GRACE_PERIOD));
assertThat(getLicensee().collectionEnabled(), is(true));
disableLicensing();
assertThat(getLicenseService().mode(), equalTo(Mode.LITE));
assertThat(getLicenseService().enabled(), is(false));
assertThat(getLicenseService().expiryDate(), greaterThan(0L));
assertThat(getLicensee().getStatus().getLicenseState(), equalTo(LicenseState.DISABLED));
assertThat(getLicensee().collectionEnabled(), is(false));
enableLicensing();
assertThat(getLicenseService().mode(), equalTo(Mode.STANDARD));
assertThat(getLicenseService().enabled(), is(true));
assertThat(getLicenseService().expiryDate(), greaterThan(0L));
assertThat(getLicensee().getStatus().getLicenseState(), isOneOf(LicenseState.ENABLED, LicenseState.GRACE_PERIOD));
assertThat(getLicensee().collectionEnabled(), is(true));
}
private LicenseService getLicenseService() {
LicenseService licenseService = internalCluster().getInstance(LicenseService.class);
assertNotNull(licenseService);
return licenseService;
private MarvelLicensee getLicensee() {
MarvelLicensee marvelLicensee = internalCluster().getInstance(MarvelLicensee.class);
assertNotNull(marvelLicensee);
return marvelLicensee;
}
public static void disableLicensing() {