Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Universal Profiling as Enterprise feature #100333

Merged
5 changes: 5 additions & 0 deletions docs/changelog/100333.yaml
@@ -0,0 +1,5 @@
pr: 100333
summary: Enable Universal Profiling as Enterprise feature
area: Application
type: enhancement
issues: []
4 changes: 4 additions & 0 deletions docs/reference/rest-api/info.asciidoc
Expand Up @@ -168,6 +168,10 @@ Example response:
"enterprise_search": {
"available": true,
"enabled": true
},
"universal_profiling": {
"available": true,
"enabled": true
}
},
"tagline" : "You know, for X"
Expand Down
4 changes: 4 additions & 0 deletions docs/reference/rest-api/usage.asciidoc
Expand Up @@ -473,6 +473,10 @@ GET /_xpack/usage
"min_rule_count": 0,
"max_rule_count": 0
}
},
"universal_profiling" : {
"available" : true,
"enabled" : true
}
}
------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions server/src/main/java/org/elasticsearch/TransportVersions.java
Expand Up @@ -135,6 +135,8 @@ static TransportVersion def(int id) {
public static final TransportVersion NESTED_KNN_VECTOR_QUERY_V = def(8_511_00_0);
public static final TransportVersion ML_PACKAGE_LOADER_PLATFORM_ADDED = def(8_512_00_0);
public static final TransportVersion PLUGIN_DESCRIPTOR_OPTIONAL_CLASSNAME = def(8_513_00_0);
public static final TransportVersion UNIVERSAL_PROFILING_LICENSE_ADDED = def(8_514_00_0);

/*
* STOP! READ THIS FIRST! No, really,
* ____ _____ ___ ____ _ ____ _____ _ ____ _____ _ _ ___ ____ _____ ___ ____ ____ _____ _
Expand Down
Expand Up @@ -23,6 +23,7 @@
import org.elasticsearch.xpack.core.aggregatemetric.AggregateMetricFeatureSetUsage;
import org.elasticsearch.xpack.core.analytics.AnalyticsFeatureSetUsage;
import org.elasticsearch.xpack.core.application.EnterpriseSearchFeatureSetUsage;
import org.elasticsearch.xpack.core.application.ProfilingUsage;
import org.elasticsearch.xpack.core.archive.ArchiveFeatureSetUsage;
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata;
import org.elasticsearch.xpack.core.datastreams.DataStreamFeatureSetUsage;
Expand Down Expand Up @@ -277,7 +278,8 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
XPackFeatureSet.Usage.class,
XPackField.ENTERPRISE_SEARCH,
EnterpriseSearchFeatureSetUsage::new
)
),
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.UNIVERSAL_PROFILING, ProfilingUsage::new)
).filter(Objects::nonNull).toList();
}

Expand Down
Expand Up @@ -85,6 +85,8 @@ public final class XPackField {

/** Name constant for the redact processor feature. */
public static final String REDACT_PROCESSOR = "redact_processor";
/* Name for Universal Profiling. */
public static final String UNIVERSAL_PROFILING = "universal_profiling";

private XPackField() {}

Expand Down
Expand Up @@ -50,6 +50,7 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
public static final XPackInfoFeatureAction AGGREGATE_METRIC = new XPackInfoFeatureAction(XPackField.AGGREGATE_METRIC);
public static final XPackInfoFeatureAction ARCHIVE = new XPackInfoFeatureAction(XPackField.ARCHIVE);
public static final XPackInfoFeatureAction ENTERPRISE_SEARCH = new XPackInfoFeatureAction(XPackField.ENTERPRISE_SEARCH);
public static final XPackInfoFeatureAction UNIVERSAL_PROFILING = new XPackInfoFeatureAction(XPackField.UNIVERSAL_PROFILING);

public static final List<XPackInfoFeatureAction> ALL;
static {
Expand Down Expand Up @@ -80,7 +81,8 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
DATA_TIERS,
AGGREGATE_METRIC,
ARCHIVE,
ENTERPRISE_SEARCH
ENTERPRISE_SEARCH,
UNIVERSAL_PROFILING
)
);
ALL = Collections.unmodifiableList(actions);
Expand Down
Expand Up @@ -50,6 +50,7 @@ public class XPackUsageFeatureAction extends ActionType<XPackUsageFeatureRespons
public static final XPackUsageFeatureAction HEALTH = new XPackUsageFeatureAction(XPackField.HEALTH_API);
public static final XPackUsageFeatureAction REMOTE_CLUSTERS = new XPackUsageFeatureAction(XPackField.REMOTE_CLUSTERS);
public static final XPackUsageFeatureAction ENTERPRISE_SEARCH = new XPackUsageFeatureAction(XPackField.ENTERPRISE_SEARCH);
public static final XPackUsageFeatureAction UNIVERSAL_PROFILING = new XPackUsageFeatureAction(XPackField.UNIVERSAL_PROFILING);

static final List<XPackUsageFeatureAction> ALL = List.of(
AGGREGATE_METRIC,
Expand Down Expand Up @@ -78,7 +79,8 @@ public class XPackUsageFeatureAction extends ActionType<XPackUsageFeatureRespons
ARCHIVE,
HEALTH,
REMOTE_CLUSTERS,
ENTERPRISE_SEARCH
ENTERPRISE_SEARCH,
UNIVERSAL_PROFILING
);

// public for testing
Expand Down
@@ -0,0 +1,31 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.core.application;

import org.elasticsearch.TransportVersion;
import org.elasticsearch.TransportVersions;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.XPackField;

import java.io.IOException;

public class ProfilingUsage extends XPackFeatureSet.Usage {
public ProfilingUsage(StreamInput input) throws IOException {
super(input);
}

public ProfilingUsage(boolean available, boolean enabled) {
super(XPackField.UNIVERSAL_PROFILING, available, enabled);
}

@Override
public TransportVersion getMinimalSupportedVersion() {
return TransportVersions.UNIVERSAL_PROFILING_LICENSE_ADDED;
}
}
@@ -0,0 +1,25 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.profiling;

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;

import java.nio.file.Path;

public class LocalStateProfilingXPackPlugin extends LocalStateCompositeXPackPlugin {
public LocalStateProfilingXPackPlugin(final Settings settings, final Path configPath) {
super(settings, configPath);
plugins.add(new ProfilingPlugin(settings) {
@Override
protected ProfilingLicenseChecker createLicenseChecker() {
return new ProfilingLicenseChecker(LocalStateProfilingXPackPlugin.this::getLicenseState);
}
});
}
}
Expand Up @@ -14,11 +14,11 @@
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.datastreams.DataStreamsPlugin;
import org.elasticsearch.license.LicenseSettings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.transport.netty4.Netty4Plugin;
import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.ilm.LifecycleSettings;
import org.elasticsearch.xpack.ilm.IndexLifecycle;
Expand All @@ -37,9 +37,8 @@ public abstract class ProfilingTestCase extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return List.of(
LocalStateCompositeXPackPlugin.class,
DataStreamsPlugin.class,
ProfilingPlugin.class,
LocalStateProfilingXPackPlugin.class,
IndexLifecycle.class,
UnsignedLongMapperPlugin.class,
VersionFieldPlugin.class,
Expand All @@ -58,6 +57,7 @@ protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) {
// .put(LicenseSettings.SELF_GENERATED_LICENSE_TYPE.getKey(), "trial")
// Disable ILM history index so that the tests don't have to clean it up
.put(LifecycleSettings.LIFECYCLE_HISTORY_INDEX_ENABLED_SETTING.getKey(), false)
.put(LicenseSettings.SELF_GENERATED_LICENSE_TYPE.getKey(), "trial")
.build();
}

Expand Down
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.profiling;

import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction;

public class ProfilingInfoTransportAction extends XPackInfoFeatureTransportAction {
private final boolean enabled;
private final ProfilingLicenseChecker licenseChecker;

@Inject
public ProfilingInfoTransportAction(
TransportService transportService,
ActionFilters actionFilters,
Settings settings,
ProfilingLicenseChecker licenseChecker
) {
super(XPackInfoFeatureAction.UNIVERSAL_PROFILING.name(), transportService, actionFilters);
this.enabled = XPackSettings.PROFILING_ENABLED.get(settings);
this.licenseChecker = licenseChecker;
}

@Override
public String name() {
return XPackField.UNIVERSAL_PROFILING;
}

@Override
public boolean available() {
return licenseChecker.isSupportedLicense();
}

@Override
public boolean enabled() {
return enabled;
}
}
@@ -0,0 +1,39 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.profiling;

import org.elasticsearch.license.License;
import org.elasticsearch.license.LicenseUtils;
import org.elasticsearch.license.LicensedFeature;
import org.elasticsearch.license.XPackLicenseState;

import java.util.function.Supplier;

public final class ProfilingLicenseChecker {
private static final LicensedFeature.Momentary UNIVERSAL_PROFILING_FEATURE = LicensedFeature.momentary(
null,
"universal_profiling",
License.OperationMode.ENTERPRISE
);

private final Supplier<XPackLicenseState> licenseStateResolver;

public ProfilingLicenseChecker(Supplier<XPackLicenseState> licenseStateResolver) {
this.licenseStateResolver = licenseStateResolver;
}

public boolean isSupportedLicense() {
return UNIVERSAL_PROFILING_FEATURE.checkWithoutTracking(licenseStateResolver.get());
}

public void requireSupportedLicense() {
if (UNIVERSAL_PROFILING_FEATURE.check(licenseStateResolver.get()) == false) {
throw LicenseUtils.newComplianceException(UNIVERSAL_PROFILING_FEATURE.getName());
}
}
}
Expand Up @@ -39,7 +39,10 @@
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xpack.core.XPackPlugin;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction;

import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -108,10 +111,12 @@ public Collection<Object> createComponents(
registry.get().initialize();
indexManager.get().initialize();
dataStreamManager.get().initialize();
return List.of(registry.get(), indexManager.get(), dataStreamManager.get());
} else {
return Collections.emptyList();
}
return Collections.singletonList(createLicenseChecker());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #97546 (comment) for context on why we are returning the license checker in all cases (but no other components).

}

protected ProfilingLicenseChecker createLicenseChecker() {
return new ProfilingLicenseChecker(XPackPlugin::getSharedLicenseState);
}

public void updateCheckOutdatedIndices(boolean newValue) {
Expand Down Expand Up @@ -179,7 +184,9 @@ public static ExecutorBuilder<?> responseExecutorBuilder() {
return List.of(
new ActionHandler<>(GetStackTracesAction.INSTANCE, TransportGetStackTracesAction.class),
new ActionHandler<>(GetFlamegraphAction.INSTANCE, TransportGetFlamegraphAction.class),
new ActionHandler<>(GetStatusAction.INSTANCE, TransportGetStatusAction.class)
new ActionHandler<>(GetStatusAction.INSTANCE, TransportGetStatusAction.class),
new ActionHandler<>(XPackUsageFeatureAction.UNIVERSAL_PROFILING, ProfilingUsageTransportAction.class),
new ActionHandler<>(XPackInfoFeatureAction.UNIVERSAL_PROFILING, ProfilingInfoTransportAction.class)
);
}

Expand Down
@@ -0,0 +1,64 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.profiling;

import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.protocol.xpack.XPackUsageRequest;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureTransportAction;
import org.elasticsearch.xpack.core.application.ProfilingUsage;

public class ProfilingUsageTransportAction extends XPackUsageFeatureTransportAction {
private final ProfilingLicenseChecker licenseChecker;

private final boolean enabled;

@Inject
public ProfilingUsageTransportAction(
TransportService transportService,
ClusterService clusterService,
ThreadPool threadPool,
ActionFilters actionFilters,
IndexNameExpressionResolver indexNameExpressionResolver,
ProfilingLicenseChecker licenseChecker,
Settings settings
) {
super(
XPackUsageFeatureAction.UNIVERSAL_PROFILING.name(),
transportService,
clusterService,
threadPool,
actionFilters,
indexNameExpressionResolver
);
this.licenseChecker = licenseChecker;
this.enabled = XPackSettings.PROFILING_ENABLED.get(settings);
}

@Override
protected void masterOperation(
Task task,
XPackUsageRequest request,
ClusterState state,
ActionListener<XPackUsageFeatureResponse> listener
) {
ProfilingUsage profilingUsage = new ProfilingUsage(licenseChecker.isSupportedLicense(), enabled);
listener.onResponse(new XPackUsageFeatureResponse(profilingUsage));
}
}