Switch to NamedWriteable pull based extension in xpack

This is the xplugins side of elastic/elasticsearchelastic/elasticsearch#19764. It converts
the one use of registering custom NamedWriteable readers in xpack for
xpack feature sets to register them up front with the new pull based
registration.

Original commit: elastic/x-pack-elasticsearch@48e2020816
This commit is contained in:
Ryan Ernst 2016-08-02 16:00:06 -07:00
parent b498fd32a2
commit cdae14a5b9
11 changed files with 61 additions and 103 deletions

View File

@ -5,16 +5,15 @@
*/
package org.elasticsearch.xpack.graph;
import java.io.IOException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.XPackFeatureSet;
import java.io.IOException;
/**
*
*/
@ -24,10 +23,9 @@ public class GraphFeatureSet implements XPackFeatureSet {
private final XPackLicenseState licenseState;
@Inject
public GraphFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, NamedWriteableRegistry namedWriteableRegistry) {
public GraphFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState) {
this.enabled = Graph.enabled(settings);
this.licenseState = licenseState;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Graph.NAME), Usage::new);
}
@Override
@ -55,7 +53,7 @@ public class GraphFeatureSet implements XPackFeatureSet {
return new Usage(available(), enabled());
}
static class Usage extends XPackFeatureSet.Usage {
public static class Usage extends XPackFeatureSet.Usage {
public Usage(StreamInput input) throws IOException {
super(input);

View File

@ -5,17 +5,13 @@
*/
package org.elasticsearch.xpack.graph;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@ -24,21 +20,14 @@ import static org.mockito.Mockito.when;
public class GraphFeatureSetTests extends ESTestCase {
private XPackLicenseState licenseState;
private NamedWriteableRegistry namedWriteableRegistry;
@Before
public void init() throws Exception {
licenseState = mock(XPackLicenseState.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class);
}
public void testWritableRegistration() throws Exception {
new GraphFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry);
verify(namedWriteableRegistry).register(eq(GraphFeatureSet.Usage.class), eq("xpack.usage.graph"), anyObject());
}
public void testAvailable() throws Exception {
GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry);
GraphFeatureSet featureSet = new GraphFeatureSet(Settings.EMPTY, licenseState);
boolean available = randomBoolean();
when(licenseState.isGraphAllowed()).thenReturn(available);
assertThat(featureSet.available(), is(available));
@ -54,7 +43,7 @@ public class GraphFeatureSetTests extends ESTestCase {
} else {
settings.put("xpack.graph.enabled", enabled);
}
GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licenseState, namedWriteableRegistry);
GraphFeatureSet featureSet = new GraphFeatureSet(settings.build(), licenseState);
assertThat(featureSet.enabled(), is(enabled));
}

View File

@ -5,9 +5,12 @@
*/
package org.elasticsearch.xpack.monitoring;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
@ -17,10 +20,6 @@ import org.elasticsearch.xpack.XPackFeatureSet;
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporter;
import org.elasticsearch.xpack.monitoring.agent.exporter.Exporters;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@ -31,12 +30,10 @@ public class MonitoringFeatureSet implements XPackFeatureSet {
private final Exporters exporters;
@Inject
public MonitoringFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, @Nullable Exporters exporters,
NamedWriteableRegistry namedWriteableRegistry) {
public MonitoringFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, @Nullable Exporters exporters) {
this.enabled = MonitoringSettings.ENABLED.get(settings);
this.licenseState = licenseState;
this.exporters = exporters;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Monitoring.NAME), Usage::new);
}
@Override
@ -79,7 +76,7 @@ public class MonitoringFeatureSet implements XPackFeatureSet {
return usage;
}
static class Usage extends XPackFeatureSet.Usage {
public static class Usage extends XPackFeatureSet.Usage {
private static final String ENABLED_EXPORTERS_XFIELD = "enabled_exporters";

View File

@ -5,7 +5,9 @@
*/
package org.elasticsearch.xpack.monitoring;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import java.util.ArrayList;
import java.util.List;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
@ -17,16 +19,10 @@ import org.elasticsearch.xpack.monitoring.agent.exporter.local.LocalExporter;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.junit.Before;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@ -35,23 +31,16 @@ import static org.mockito.Mockito.when;
public class MonitoringFeatureSetTests extends ESTestCase {
private XPackLicenseState licenseState;
private NamedWriteableRegistry namedWriteableRegistry;
private Exporters exporters;
@Before
public void init() throws Exception {
licenseState = mock(XPackLicenseState.class);
exporters = mock(Exporters.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class);
}
public void testWritableRegistration() throws Exception {
new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters, namedWriteableRegistry);
verify(namedWriteableRegistry).register(eq(MonitoringFeatureSet.Usage.class), eq("xpack.usage.monitoring"), anyObject());
}
public void testAvailable() throws Exception {
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters, namedWriteableRegistry);
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters);
boolean available = randomBoolean();
when(licenseState.isMonitoringAllowed()).thenReturn(available);
assertThat(featureSet.available(), is(available));
@ -61,12 +50,12 @@ public class MonitoringFeatureSetTests extends ESTestCase {
boolean enabled = randomBoolean();
Settings.Builder settings = Settings.builder();
settings.put("xpack.monitoring.enabled", enabled);
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(settings.build(), licenseState, exporters, namedWriteableRegistry);
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(settings.build(), licenseState, exporters);
assertThat(featureSet.enabled(), is(enabled));
}
public void testEnabledDefault() throws Exception {
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters, namedWriteableRegistry);
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters);
assertThat(featureSet.enabled(), is(true));
}
@ -103,7 +92,7 @@ public class MonitoringFeatureSetTests extends ESTestCase {
}
when(exporters.iterator()).thenReturn(exporterList.iterator());
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters, namedWriteableRegistry);
MonitoringFeatureSet featureSet = new MonitoringFeatureSet(Settings.EMPTY, licenseState, exporters);
XPackFeatureSet.Usage usage = featureSet.usage();
assertThat(usage.name(), is(featureSet.name()));
assertThat(usage.enabled(), is(featureSet.enabled()));

View File

@ -52,9 +52,8 @@ public class SecurityFeatureSet implements XPackFeatureSet {
@Inject
public SecurityFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, @Nullable Realms realms,
NamedWriteableRegistry namedWriteableRegistry, @Nullable CompositeRolesStore rolesStore,
@Nullable IPFilter ipFilter, @Nullable AuditTrailService auditTrailService,
@Nullable CryptoService cryptoService) {
@Nullable CompositeRolesStore rolesStore, @Nullable IPFilter ipFilter,
@Nullable AuditTrailService auditTrailService, @Nullable CryptoService cryptoService) {
this.enabled = Security.enabled(settings);
this.licenseState = licenseState;
this.realms = realms;
@ -63,7 +62,6 @@ public class SecurityFeatureSet implements XPackFeatureSet {
this.ipFilter = ipFilter;
this.auditTrailService = auditTrailService;
this.cryptoService = cryptoService;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Security.NAME), Usage::new);
}
@Override
@ -139,7 +137,7 @@ public class SecurityFeatureSet implements XPackFeatureSet {
return Collections.singletonMap("enabled", cryptoService != null && cryptoService.isEncryptionEnabled());
}
static class Usage extends XPackFeatureSet.Usage {
public static class Usage extends XPackFeatureSet.Usage {
private static final String REALMS_XFIELD = "realms";
private static final String ROLES_XFIELD = "roles";

View File

@ -5,8 +5,12 @@
*/
package org.elasticsearch.xpack.security;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.test.ESTestCase;
@ -23,20 +27,12 @@ import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.junit.After;
import org.junit.Before;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class SecurityFeatureSetTests extends ESTestCase {
@ -44,7 +40,6 @@ public class SecurityFeatureSetTests extends ESTestCase {
private Settings settings;
private XPackLicenseState licenseState;
private Realms realms;
private NamedWriteableRegistry namedWriteableRegistry;
private IPFilter ipFilter;
private CompositeRolesStore rolesStore;
private AuditTrailService auditTrail;
@ -55,7 +50,6 @@ public class SecurityFeatureSetTests extends ESTestCase {
settings = Settings.builder().put("path.home", createTempDir()).build();
licenseState = mock(XPackLicenseState.class);
realms = mock(Realms.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class);
ipFilter = mock(IPFilter.class);
rolesStore = mock(CompositeRolesStore.class);
auditTrail = mock(AuditTrailService.class);
@ -67,13 +61,8 @@ public class SecurityFeatureSetTests extends ESTestCase {
AnonymousUser.initialize(Settings.EMPTY);
}
public void testWritableRegistration() throws Exception {
new SecurityFeatureSet(settings, licenseState, realms, namedWriteableRegistry, rolesStore, ipFilter, auditTrail, cryptoService);
verify(namedWriteableRegistry).register(eq(SecurityFeatureSet.Usage.class), eq("xpack.usage.security"), anyObject());
}
public void testAvailable() throws Exception {
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, namedWriteableRegistry, rolesStore,
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, rolesStore,
ipFilter, auditTrail, cryptoService);
boolean available = randomBoolean();
when(licenseState.isAuthAllowed()).thenReturn(available);
@ -86,13 +75,13 @@ public class SecurityFeatureSetTests extends ESTestCase {
.put(this.settings)
.put("xpack.security.enabled", enabled)
.build();
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, namedWriteableRegistry, rolesStore,
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, rolesStore,
ipFilter, auditTrail, cryptoService);
assertThat(featureSet.enabled(), is(enabled));
}
public void testEnabledDefault() throws Exception {
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, namedWriteableRegistry, rolesStore,
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings, licenseState, realms, rolesStore,
ipFilter, auditTrail, cryptoService);
assertThat(featureSet.enabled(), is(true));
}
@ -164,7 +153,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
AnonymousUser.initialize(Settings.builder().put(AnonymousUser.ROLES_SETTING.getKey(), "foo").build());
}
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState, realms, namedWriteableRegistry, rolesStore,
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState, realms, rolesStore,
ipFilter, auditTrail, cryptoService);
XPackFeatureSet.Usage usage = featureSet.usage();
assertThat(usage, is(notNullValue()));

View File

@ -113,7 +113,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase {
Collections.emptyMap(), Collections.emptyMap());
SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap());
mapperService = new MapperService(indexSettings, analysisService, similarityService,
new IndicesModule(new NamedWriteableRegistry(), emptyList()).getMapperRegistry(), () -> null);
new IndicesModule(emptyList()).getMapperRegistry(), () -> null);
ShardId shardId = new ShardId(index, 0);
licenseState = mock(XPackLicenseState.class);

View File

@ -61,7 +61,7 @@ public interface XPackFeatureSet {
@Override
public String getWriteableName() {
return writeableName(name);
return name;
}
@Override
@ -81,10 +81,6 @@ public interface XPackFeatureSet {
builder.field(AVAILABLE_XFIELD, available);
builder.field(ENABLED_XFIELD, enabled);
}
public static String writeableName(String featureName) {
return "xpack.usage." + featureName;
}
}
}

View File

@ -10,6 +10,7 @@ import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -31,6 +32,7 @@ import org.elasticsearch.common.inject.Binder;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.inject.multibindings.Multibinder;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
@ -63,7 +65,9 @@ import org.elasticsearch.xpack.common.text.TextTemplateModule;
import org.elasticsearch.xpack.extensions.XPackExtension;
import org.elasticsearch.xpack.extensions.XPackExtensionsService;
import org.elasticsearch.xpack.graph.Graph;
import org.elasticsearch.xpack.graph.GraphFeatureSet;
import org.elasticsearch.xpack.monitoring.Monitoring;
import org.elasticsearch.xpack.monitoring.MonitoringFeatureSet;
import org.elasticsearch.xpack.monitoring.MonitoringSettings;
import org.elasticsearch.xpack.notification.Notification;
import org.elasticsearch.xpack.notification.email.Account;
@ -72,11 +76,13 @@ import org.elasticsearch.xpack.rest.action.RestXPackInfoAction;
import org.elasticsearch.xpack.rest.action.RestXPackUsageAction;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.SecurityFeatureSet;
import org.elasticsearch.xpack.security.authc.AuthenticationService;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.support.clock.SystemClock;
import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.WatcherFeatureSet;
import org.elasticsearch.xpack.watcher.support.WatcherScript;
public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, IngestPlugin {
@ -321,6 +327,16 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
return security.getProcessors(parameters);
}
@Override
public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
return Arrays.asList(
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, Security.NAME, SecurityFeatureSet.Usage::new),
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, Watcher.NAME, WatcherFeatureSet.Usage::new),
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, Monitoring.NAME, MonitoringFeatureSet.Usage::new),
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, Graph.NAME, GraphFeatureSet.Usage::new)
);
}
public void onIndexModule(IndexModule module) {
security.onIndexModule(module);
}

View File

@ -5,9 +5,12 @@
*/
package org.elasticsearch.xpack.watcher;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
@ -15,10 +18,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.XPackFeatureSet;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
/**
*
*/
@ -29,12 +28,10 @@ public class WatcherFeatureSet implements XPackFeatureSet {
private final WatcherService watcherService;
@Inject
public WatcherFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, NamedWriteableRegistry namedWriteableRegistry,
@Nullable WatcherService watcherService) {
public WatcherFeatureSet(Settings settings, @Nullable XPackLicenseState licenseState, @Nullable WatcherService watcherService) {
this.watcherService = watcherService;
this.enabled = Watcher.enabled(settings);
this.licenseState = licenseState;
namedWriteableRegistry.register(Usage.class, Usage.writeableName(Watcher.NAME), Usage::new);
}
@Override
@ -62,7 +59,7 @@ public class WatcherFeatureSet implements XPackFeatureSet {
return new Usage(available(), enabled(), watcherService != null ? watcherService.usageStats() : Collections.emptyMap());
}
static class Usage extends XPackFeatureSet.Usage {
public static class Usage extends XPackFeatureSet.Usage {
private final Map<String, Object> stats;

View File

@ -5,7 +5,9 @@
*/
package org.elasticsearch.xpack.watcher;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import java.util.HashMap;
import java.util.Map;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -14,17 +16,11 @@ import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.junit.Before;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@ -33,23 +29,16 @@ import static org.mockito.Mockito.when;
public class WatcherFeatureSetTests extends ESTestCase {
private XPackLicenseState licenseState;
private NamedWriteableRegistry namedWriteableRegistry;
private WatcherService watcherService;
@Before
public void init() throws Exception {
licenseState = mock(XPackLicenseState.class);
namedWriteableRegistry = mock(NamedWriteableRegistry.class);
watcherService = mock(WatcherService.class);
}
public void testWritableRegistration() throws Exception {
new WatcherFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry, watcherService);
verify(namedWriteableRegistry).register(eq(WatcherFeatureSet.Usage.class), eq("xpack.usage.watcher"), anyObject());
}
public void testAvailable() throws Exception {
WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry, watcherService);
WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licenseState, watcherService);
boolean available = randomBoolean();
when(licenseState.isWatcherAllowed()).thenReturn(available);
assertThat(featureSet.available(), is(available));
@ -65,7 +54,7 @@ public class WatcherFeatureSetTests extends ESTestCase {
} else {
settings.put("xpack.watcher.enabled", enabled);
}
WatcherFeatureSet featureSet = new WatcherFeatureSet(settings.build(), licenseState, namedWriteableRegistry, watcherService);
WatcherFeatureSet featureSet = new WatcherFeatureSet(settings.build(), licenseState, watcherService);
assertThat(featureSet.enabled(), is(enabled));
}
@ -74,7 +63,7 @@ public class WatcherFeatureSetTests extends ESTestCase {
statsMap.put("foo", "bar");
when(watcherService.usageStats()).thenReturn(statsMap);
WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licenseState, namedWriteableRegistry, watcherService);
WatcherFeatureSet featureSet = new WatcherFeatureSet(Settings.EMPTY, licenseState, watcherService);
XContentBuilder builder = jsonBuilder();
featureSet.usage().toXContent(builder, ToXContent.EMPTY_PARAMS);