diff --git a/src/main/java/org/elasticsearch/license/plugin/LicenseModule.java b/src/main/java/org/elasticsearch/license/plugin/LicenseModule.java index 78506b1c402..5a1f3e014a6 100644 --- a/src/main/java/org/elasticsearch/license/plugin/LicenseModule.java +++ b/src/main/java/org/elasticsearch/license/plugin/LicenseModule.java @@ -13,7 +13,6 @@ import org.elasticsearch.license.plugin.core.LicensesService; public class LicenseModule extends AbstractModule { @Override protected void configure() { - //TODO: bind LicensesManagementService and LicensesValidationService to LicensesServices instead bind(ESLicenseManager.class).in(Scopes.SINGLETON); bind(LicensesService.class).in(Scopes.SINGLETON); } diff --git a/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java b/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java index 57658c6e69d..63cae8b1816 100644 --- a/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java +++ b/src/main/java/org/elasticsearch/license/plugin/core/LicensesService.java @@ -313,12 +313,17 @@ public class LicensesService extends AbstractLifecycleComponent if (!pendingRegistrations.isEmpty()) { ListenerHolder pendingRegistrationLister; while ((pendingRegistrationLister = pendingRegistrations.poll()) != null) { - logger.info("trying to register pending listener for " + pendingRegistrationLister.feature); - registerListener(pendingRegistrationLister); + boolean masterAvailable = registerListener(pendingRegistrationLister); + logger.info("trying to register pending listener for " + pendingRegistrationLister.feature + " masterAvailable: " + masterAvailable); + if (!masterAvailable) { + // if the master is not available do not, break out of trying pendingRegistrations + break; + } } } // notify all interested plugins + logger.info("LicensesService: cluster state changed"); if (checkIfUpdatedMetaData(event)) { final LicensesMetaData currentLicensesMetaData = event.state().getMetaData().custom(LicensesMetaData.TYPE); // Change to debug @@ -360,8 +365,12 @@ public class LicensesService extends AbstractLifecycleComponent * then notifies features to be disabled * * @param listenerHolder of the feature to register + * + * @return true if registration has been completed, false otherwise (if masterNode is not available) */ - private void registerListener(final ListenerHolder listenerHolder) { + private boolean registerListener(final ListenerHolder listenerHolder) { + logger.info("Registering listener for " + listenerHolder.feature); + LicensesMetaData currentMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE); if (!hasLicenseForFeature(listenerHolder.feature, currentMetaData)) { // does not have actual license so generate a trial license @@ -371,31 +380,35 @@ public class LicensesService extends AbstractLifecycleComponent RegisterTrialLicenseRequest request = new RegisterTrialLicenseRequest(listenerHolder.feature, new TimeValue(options.durationInDays, TimeUnit.DAYS), options.maxNodes); if (clusterService.state().nodes().localNodeMaster()) { + logger.info("Executing trial license request"); registerTrialLicense(request); } else { DiscoveryNode masterNode = clusterService.state().nodes().masterNode(); - logger.info("has STATE_NOT_RECOVERED_BLOCK: " + clusterService.state().blocks().hasGlobalBlock(GatewayService.STATE_NOT_RECOVERED_BLOCK) - + " has masterNode: " + (masterNode != null)); if (masterNode != null) { + logger.info("Sending trial license request to master"); transportService.sendRequest(masterNode, REGISTER_TRIAL_LICENSE_ACTION_NAME, request, EmptyTransportResponseHandler.INSTANCE_SAME); } else { // could not sent register trial license request to master + logger.info("Store as pendingRegistration [master not available yet]"); pendingRegistrations.add(listenerHolder); + return false; } } } else { // notify feature as clusterChangedEvent may not happen // as no trial or signed license has been found for feature // Change to debug - logger.info("calling notifyFeatures from registerListeners"); + logger.info("Calling notifyFeatures [no trial license spec provided]"); notifyFeatures(currentMetaData); } } else { // signed license already found for the new registered // feature, notify feature on registration + logger.info("Calling notifyFeatures [signed license available]"); notifyFeatures(currentMetaData); } + return true; } private boolean hasLicenseForFeature(String feature, LicensesMetaData currentLicensesMetaData) { @@ -481,7 +494,12 @@ public class LicensesService extends AbstractLifecycleComponent LicensesWrapper licensesWrapper = LicensesWrapper.wrap(currentLicensesMetaData); long nextScheduleFrequency = -1l; long offset = TimeValue.timeValueMinutes(1).getMillis(); + StringBuilder sb = new StringBuilder("Registered listeners: [ "); for (ListenerHolder listenerHolder : registeredListeners) { + + sb.append(listenerHolder.feature); + sb.append(" "); + long expiryDate = -1l; if (hasLicenseForFeature(listenerHolder.feature, currentLicensesMetaData)) { final Map effectiveLicenses = getEffectiveLicenses(currentLicensesMetaData); @@ -508,6 +526,8 @@ public class LicensesService extends AbstractLifecycleComponent listenerHolder.disableFeatureIfNeeded(); } } + sb.append("]"); + logger.info(sb.toString()); if (nextScheduleFrequency == -1l) { nextScheduleFrequency = TimeValue.timeValueMinutes(5).getMillis(); diff --git a/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java b/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java index 88c0b386ffe..65e64d227ad 100644 --- a/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java +++ b/src/main/java/org/elasticsearch/license/plugin/rest/RestGetLicenseAction.java @@ -9,13 +9,16 @@ import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.license.core.ESLicenses; +import org.elasticsearch.license.core.DateUtils; +import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.plugin.action.get.GetLicenseAction; import org.elasticsearch.license.plugin.action.get.GetLicenseRequest; import org.elasticsearch.license.plugin.action.get.GetLicenseResponse; import org.elasticsearch.rest.*; import org.elasticsearch.rest.action.support.RestBuilderListener; +import java.io.IOException; + import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.rest.RestStatus.OK; @@ -32,9 +35,53 @@ public class RestGetLicenseAction extends BaseRestHandler { client.admin().cluster().execute(GetLicenseAction.INSTANCE, new GetLicenseRequest(), new RestBuilderListener(channel) { @Override public RestResponse buildResponse(GetLicenseResponse response, XContentBuilder builder) throws Exception { - ESLicenses.toXContent(response.licenses(), builder); + toXContent(response, builder); return new BytesRestResponse(OK, builder); } }); } + + /** + * Output Format: + * { + *   "licenses" : [ + *     { + *       "uid" : ..., + *       "type" : ..., + *       "subscription_type" :..., + *       "issued_to" : ... (cluster name if one-time trial license, else value from signed license), + *       "issue_date" : YY-MM-DD (date string in UTC), + *       "expiry_date" : YY-MM-DD (date string in UTC), + *       "feature" : ..., + *       "max_nodes" : ... + *     }, + * {...} + *   ] + * } + * + * There will be only one license displayed per feature, the selected license will have the latest expiry_date + * out of all other licenses for the feature. + * + * The licenses are sorted by latest issue_date + */ + private static void toXContent(GetLicenseResponse response, XContentBuilder builder) throws IOException { + builder.startObject(); + builder.startArray("licenses"); + for (ESLicense license : response.licenses()) { + builder.startObject(); + + builder.field("uid", license.uid()); + builder.field("type", license.type().string()); + builder.field("subscription_type", license.subscriptionType().string()); + builder.field("issued_to", license.issuedTo()); + builder.field("issue_date", DateUtils.dateStringFromLongDate(license.issueDate())); + builder.field("expiry_date", DateUtils.dateStringFromLongDate(license.expiryDate())); + builder.field("feature", license.feature()); + builder.field("max_nodes", license.maxNodes()); + + builder.endObject(); + } + builder.endArray(); + builder.endObject(); + } }