Skip to content

Commit f9511f4

Browse files
authored
Add SLM support to xpack usage and info APIs (#48096)
* Add SLM support to xpack usage and info APIs This adds the missing xpack usage and info information into the `/_xpack` and `/_xpack/usage` APIs. The output now looks like: ``` GET /_xpack/usage { ... "slm" : { "available" : true, "enabled" : true, "policy_count" : 1, "policy_stats" : { "retention_runs" : 0, ... } } ``` and ``` GET /_xpack { ... "features" : { ... "slm" : { "available" : true, "enabled" : true }, ... } } ``` Relates to #43663 * Fix test expectation * Fix docs test
1 parent 1aaea69 commit f9511f4

File tree

10 files changed

+270
-15
lines changed

10 files changed

+270
-15
lines changed

docs/reference/rest-api/info.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ Example response:
107107
"available" : true,
108108
"enabled" : false
109109
},
110+
"slm" : {
111+
"available" : true,
112+
"enabled" : true
113+
},
110114
"spatial" : {
111115
"available" : true,
112116
"enabled" : true

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackClientPlugin.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@
3333
import org.elasticsearch.xpack.ccr.CCRInfoTransportAction;
3434
import org.elasticsearch.xpack.core.action.XPackInfoAction;
3535
import org.elasticsearch.xpack.core.action.XPackUsageAction;
36+
import org.elasticsearch.xpack.core.analytics.AnalyticsFeatureSetUsage;
3637
import org.elasticsearch.xpack.core.beats.BeatsFeatureSetUsage;
3738
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata;
38-
import org.elasticsearch.xpack.core.analytics.AnalyticsFeatureSetUsage;
3939
import org.elasticsearch.xpack.core.deprecation.DeprecationInfoAction;
4040
import org.elasticsearch.xpack.core.flattened.FlattenedFeatureSetUsage;
4141
import org.elasticsearch.xpack.core.frozen.FrozenIndicesFeatureSetUsage;
@@ -139,12 +139,12 @@
139139
import org.elasticsearch.xpack.core.ml.dataframe.evaluation.softclassification.Recall;
140140
import org.elasticsearch.xpack.core.ml.dataframe.evaluation.softclassification.ScoreByThresholdResult;
141141
import org.elasticsearch.xpack.core.ml.dataframe.evaluation.softclassification.SoftClassificationMetric;
142-
import org.elasticsearch.xpack.core.ml.inference.trainedmodel.TrainedModel;
143-
import org.elasticsearch.xpack.core.ml.inference.trainedmodel.tree.Tree;
144142
import org.elasticsearch.xpack.core.ml.inference.preprocessing.FrequencyEncoding;
145143
import org.elasticsearch.xpack.core.ml.inference.preprocessing.OneHotEncoding;
146144
import org.elasticsearch.xpack.core.ml.inference.preprocessing.PreProcessor;
147145
import org.elasticsearch.xpack.core.ml.inference.preprocessing.TargetMeanEncoding;
146+
import org.elasticsearch.xpack.core.ml.inference.trainedmodel.TrainedModel;
147+
import org.elasticsearch.xpack.core.ml.inference.trainedmodel.tree.Tree;
148148
import org.elasticsearch.xpack.core.ml.job.config.JobTaskState;
149149
import org.elasticsearch.xpack.core.monitoring.MonitoringFeatureSetUsage;
150150
import org.elasticsearch.xpack.core.rollup.RollupFeatureSetUsage;
@@ -188,6 +188,7 @@
188188
import org.elasticsearch.xpack.core.security.authc.support.mapper.expressiondsl.RoleMapperExpression;
189189
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivilege;
190190
import org.elasticsearch.xpack.core.security.authz.privilege.ConfigurableClusterPrivileges;
191+
import org.elasticsearch.xpack.core.slm.SLMFeatureSetUsage;
191192
import org.elasticsearch.xpack.core.slm.SnapshotLifecycleMetadata;
192193
import org.elasticsearch.xpack.core.slm.action.DeleteSnapshotLifecycleAction;
193194
import org.elasticsearch.xpack.core.slm.action.ExecuteSnapshotLifecycleAction;
@@ -206,10 +207,10 @@
206207
import org.elasticsearch.xpack.core.transform.action.PutTransformAction;
207208
import org.elasticsearch.xpack.core.transform.action.StartTransformAction;
208209
import org.elasticsearch.xpack.core.transform.action.StopTransformAction;
209-
import org.elasticsearch.xpack.core.transform.transforms.TransformTaskParams;
210-
import org.elasticsearch.xpack.core.transform.transforms.TransformState;
211210
import org.elasticsearch.xpack.core.transform.transforms.SyncConfig;
212211
import org.elasticsearch.xpack.core.transform.transforms.TimeSyncConfig;
212+
import org.elasticsearch.xpack.core.transform.transforms.TransformState;
213+
import org.elasticsearch.xpack.core.transform.transforms.TransformTaskParams;
213214
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeAction;
214215
import org.elasticsearch.xpack.core.upgrade.actions.IndexUpgradeInfoAction;
215216
import org.elasticsearch.xpack.core.vectors.VectorsFeatureSetUsage;
@@ -490,6 +491,9 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
490491
// ILM
491492
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.INDEX_LIFECYCLE,
492493
IndexLifecycleFeatureSetUsage::new),
494+
// SLM
495+
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.SNAPSHOT_LIFECYCLE,
496+
SLMFeatureSetUsage::new),
493497
// ILM - Custom Metadata
494498
new NamedWriteableRegistry.Entry(MetaData.Custom.class, IndexLifecycleMetadata.TYPE, IndexLifecycleMetadata::new),
495499
new NamedWriteableRegistry.Entry(NamedDiff.class, IndexLifecycleMetadata.TYPE,

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackField.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public final class XPackField {
3333
public static final String ROLLUP = "rollup";
3434
/** Name constant for the index lifecycle feature. */
3535
public static final String INDEX_LIFECYCLE = "ilm";
36+
/** Name constant for the snapshot lifecycle management feature. */
37+
public static final String SNAPSHOT_LIFECYCLE = "slm";
3638
/** Name constant for the CCR feature. */
3739
public static final String CCR = "ccr";
3840
/** Name constant for the transform feature. */

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
3131
public static final XPackInfoFeatureAction SQL = new XPackInfoFeatureAction(XPackField.SQL);
3232
public static final XPackInfoFeatureAction ROLLUP = new XPackInfoFeatureAction(XPackField.ROLLUP);
3333
public static final XPackInfoFeatureAction INDEX_LIFECYCLE = new XPackInfoFeatureAction(XPackField.INDEX_LIFECYCLE);
34+
public static final XPackInfoFeatureAction SNAPSHOT_LIFECYCLE = new XPackInfoFeatureAction(XPackField.SNAPSHOT_LIFECYCLE);
3435
public static final XPackInfoFeatureAction CCR = new XPackInfoFeatureAction(XPackField.CCR);
3536
public static final XPackInfoFeatureAction TRANSFORM = new XPackInfoFeatureAction(XPackField.TRANSFORM);
3637
public static final XPackInfoFeatureAction FLATTENED = new XPackInfoFeatureAction(XPackField.FLATTENED);
@@ -41,8 +42,8 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
4142
public static final XPackInfoFeatureAction ANALYTICS = new XPackInfoFeatureAction(XPackField.ANALYTICS);
4243

4344
public static final List<XPackInfoFeatureAction> ALL = Arrays.asList(
44-
SECURITY, MONITORING, WATCHER, GRAPH, MACHINE_LEARNING, LOGSTASH, SQL, ROLLUP, INDEX_LIFECYCLE, CCR, TRANSFORM, FLATTENED,
45-
VECTORS, VOTING_ONLY, FROZEN_INDICES, SPATIAL, ANALYTICS
45+
SECURITY, MONITORING, WATCHER, GRAPH, MACHINE_LEARNING, LOGSTASH, SQL, ROLLUP, INDEX_LIFECYCLE, SNAPSHOT_LIFECYCLE, CCR,
46+
TRANSFORM, FLATTENED, VECTORS, VOTING_ONLY, FROZEN_INDICES, SPATIAL, ANALYTICS
4647
);
4748

4849
private XPackInfoFeatureAction(String name) {

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackUsageFeatureAction.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class XPackUsageFeatureAction extends ActionType<XPackUsageFeatureRespons
3131
public static final XPackUsageFeatureAction SQL = new XPackUsageFeatureAction(XPackField.SQL);
3232
public static final XPackUsageFeatureAction ROLLUP = new XPackUsageFeatureAction(XPackField.ROLLUP);
3333
public static final XPackUsageFeatureAction INDEX_LIFECYCLE = new XPackUsageFeatureAction(XPackField.INDEX_LIFECYCLE);
34+
public static final XPackUsageFeatureAction SNAPSHOT_LIFECYCLE = new XPackUsageFeatureAction(XPackField.SNAPSHOT_LIFECYCLE);
3435
public static final XPackUsageFeatureAction CCR = new XPackUsageFeatureAction(XPackField.CCR);
3536
public static final XPackUsageFeatureAction TRANSFORM = new XPackUsageFeatureAction(XPackField.TRANSFORM);
3637
public static final XPackUsageFeatureAction FLATTENED = new XPackUsageFeatureAction(XPackField.FLATTENED);
@@ -41,8 +42,8 @@ public class XPackUsageFeatureAction extends ActionType<XPackUsageFeatureRespons
4142
public static final XPackUsageFeatureAction ANALYTICS = new XPackUsageFeatureAction(XPackField.ANALYTICS);
4243

4344
public static final List<XPackUsageFeatureAction> ALL = Arrays.asList(
44-
SECURITY, MONITORING, WATCHER, GRAPH, MACHINE_LEARNING, LOGSTASH, SQL, ROLLUP, INDEX_LIFECYCLE, CCR, TRANSFORM, FLATTENED,
45-
VECTORS, VOTING_ONLY, FROZEN_INDICES, SPATIAL, ANALYTICS
45+
SECURITY, MONITORING, WATCHER, GRAPH, MACHINE_LEARNING, LOGSTASH, SQL, ROLLUP, INDEX_LIFECYCLE, SNAPSHOT_LIFECYCLE, CCR,
46+
TRANSFORM, FLATTENED, VECTORS, VOTING_ONLY, FROZEN_INDICES, SPATIAL, ANALYTICS
4647
);
4748

4849
private XPackUsageFeatureAction(String name) {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.core.slm;
8+
9+
import org.elasticsearch.common.Nullable;
10+
import org.elasticsearch.common.io.stream.StreamInput;
11+
import org.elasticsearch.common.io.stream.StreamOutput;
12+
import org.elasticsearch.common.xcontent.XContentBuilder;
13+
import org.elasticsearch.xpack.core.XPackFeatureSet;
14+
import org.elasticsearch.xpack.core.XPackField;
15+
import org.elasticsearch.xpack.slm.SnapshotLifecycleStats;
16+
17+
import java.io.IOException;
18+
import java.util.Objects;
19+
20+
public class SLMFeatureSetUsage extends XPackFeatureSet.Usage {
21+
@Nullable
22+
private final SnapshotLifecycleStats slmStats;
23+
24+
public SLMFeatureSetUsage(StreamInput in) throws IOException {
25+
super(in);
26+
this.slmStats = in.readOptionalWriteable(SnapshotLifecycleStats::new);
27+
}
28+
29+
@Override
30+
public void writeTo(StreamOutput out) throws IOException {
31+
super.writeTo(out);
32+
out.writeOptionalWriteable(this.slmStats);
33+
}
34+
35+
public SLMFeatureSetUsage(boolean available, boolean enabled, @Nullable SnapshotLifecycleStats slmStats) {
36+
super(XPackField.SNAPSHOT_LIFECYCLE, available, enabled);
37+
this.slmStats = slmStats;
38+
}
39+
40+
public SnapshotLifecycleStats getStats() {
41+
return this.slmStats;
42+
}
43+
44+
@Override
45+
protected void innerXContent(XContentBuilder builder, Params params) throws IOException {
46+
super.innerXContent(builder, params);
47+
if (slmStats != null) {
48+
builder.field("policy_count", slmStats.getMetrics().size());
49+
builder.field("policy_stats", slmStats);
50+
}
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return Objects.hash(available, enabled, slmStats);
56+
}
57+
58+
@Override
59+
public boolean equals(Object obj) {
60+
if (obj == null) {
61+
return false;
62+
}
63+
if (getClass() != obj.getClass()) {
64+
return false;
65+
}
66+
SLMFeatureSetUsage other = (SLMFeatureSetUsage) obj;
67+
return Objects.equals(available, other.available) &&
68+
Objects.equals(enabled, other.enabled) &&
69+
Objects.equals(slmStats, other.slmStats);
70+
}
71+
72+
}

x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/slm/SnapshotLifecycleRestIT.java

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import static org.elasticsearch.xpack.core.slm.history.SnapshotHistoryItem.DELETE_OPERATION;
5050
import static org.elasticsearch.xpack.core.slm.history.SnapshotHistoryStore.SLM_HISTORY_INDEX_PREFIX;
5151
import static org.elasticsearch.xpack.ilm.TimeSeriesLifecycleActionsIT.getStepKeyForIndex;
52+
import static org.hamcrest.Matchers.anyOf;
5253
import static org.hamcrest.Matchers.containsString;
5354
import static org.hamcrest.Matchers.equalTo;
5455
import static org.hamcrest.Matchers.greaterThan;
@@ -425,6 +426,76 @@ public void testBasicTimeBasedRetenion() throws Exception {
425426
}
426427
}
427428

429+
@SuppressWarnings("unchecked")
430+
public void testSLMXpackInfo() {
431+
Map<String, Object> features = (Map<String, Object>) getLocation("/_xpack").get("features");
432+
assertNotNull(features);
433+
Map<String, Object> slm = (Map<String, Object>) features.get("slm");
434+
assertNotNull(slm);
435+
assertTrue((boolean) slm.get("available"));
436+
assertTrue((boolean) slm.get("enabled"));
437+
}
438+
439+
@SuppressWarnings("unchecked")
440+
public void testSLMXpackUsage() throws Exception {
441+
Map<String, Object> slm = (Map<String, Object>) getLocation("/_xpack/usage").get("slm");
442+
assertNotNull(slm);
443+
assertTrue((boolean) slm.get("available"));
444+
assertTrue((boolean) slm.get("enabled"));
445+
assertThat(slm.get("policy_count"), anyOf(equalTo(null), equalTo(0)));
446+
447+
// Create a snapshot repo
448+
initializeRepo("repo");
449+
// Create a policy with a retention period of 1 millisecond
450+
createSnapshotPolicy("policy", "snap", "1 2 3 4 5 ?", "repo", "*", true,
451+
new SnapshotRetentionConfiguration(TimeValue.timeValueMillis(1), null, null));
452+
final String snapshotName = executePolicy("policy");
453+
454+
// Check that the executed snapshot is created
455+
assertBusy(() -> {
456+
try {
457+
logger.info("--> checking for snapshot creation...");
458+
Response response = client().performRequest(new Request("GET", "/_snapshot/repo/" + snapshotName));
459+
Map<String, Object> snapshotResponseMap;
460+
try (InputStream is = response.getEntity().getContent()) {
461+
snapshotResponseMap = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true);
462+
}
463+
assertThat(snapshotResponseMap.size(), greaterThan(0));
464+
} catch (ResponseException e) {
465+
fail("expected snapshot to exist but it does not: " + EntityUtils.toString(e.getResponse().getEntity()));
466+
}
467+
});
468+
469+
// Wait for stats to be updated
470+
assertBusy(() -> {
471+
logger.info("--> checking for stats to be updated...");
472+
Map<String, Object> stats = getSLMStats();
473+
Map<String, Object> policyStats = policyStatsAsMap(stats);
474+
Map<String, Object> policyIdStats = (Map<String, Object>) policyStats.get("policy");
475+
assertNotNull(policyIdStats);
476+
});
477+
478+
slm = (Map<String, Object>) getLocation("/_xpack/usage").get("slm");
479+
assertNotNull(slm);
480+
assertTrue((boolean) slm.get("available"));
481+
assertTrue((boolean) slm.get("enabled"));
482+
assertThat("got: " + slm, slm.get("policy_count"), equalTo(1));
483+
assertNotNull(slm.get("policy_stats"));
484+
}
485+
486+
public Map<String, Object> getLocation(String path) {
487+
try {
488+
Response executeRepsonse = client().performRequest(new Request("GET", path));
489+
try (XContentParser parser = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
490+
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, EntityUtils.toByteArray(executeRepsonse.getEntity()))) {
491+
return parser.map();
492+
}
493+
} catch (Exception e) {
494+
fail("failed to execute GET request to " + path + " - got: " + e);
495+
throw new RuntimeException(e);
496+
}
497+
}
498+
428499
/**
429500
* Execute the given policy and return the generated snapshot name
430501
*/

x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycle.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
import org.elasticsearch.xpack.ilm.action.TransportRetryAction;
9595
import org.elasticsearch.xpack.ilm.action.TransportStartILMAction;
9696
import org.elasticsearch.xpack.ilm.action.TransportStopILMAction;
97+
import org.elasticsearch.xpack.slm.SLMInfoTransportAction;
98+
import org.elasticsearch.xpack.slm.SLMUsageTransportAction;
9799
import org.elasticsearch.xpack.slm.SnapshotLifecycleService;
98100
import org.elasticsearch.xpack.slm.SnapshotLifecycleTask;
99101
import org.elasticsearch.xpack.slm.SnapshotRetentionService;
@@ -254,13 +256,15 @@ public List<RestHandler> getRestHandlers(Settings settings, RestController restC
254256

255257
@Override
256258
public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
257-
var usageAction =
258-
new ActionHandler<>(XPackUsageFeatureAction.INDEX_LIFECYCLE, IndexLifecycleUsageTransportAction.class);
259-
var infoAction =
260-
new ActionHandler<>(XPackInfoFeatureAction.INDEX_LIFECYCLE, IndexLifecycleInfoTransportAction.class);
259+
var ilmUsageAction = new ActionHandler<>(XPackUsageFeatureAction.INDEX_LIFECYCLE, IndexLifecycleUsageTransportAction.class);
260+
var ilmInfoAction = new ActionHandler<>(XPackInfoFeatureAction.INDEX_LIFECYCLE, IndexLifecycleInfoTransportAction.class);
261+
var slmUsageAction = new ActionHandler<>(XPackUsageFeatureAction.SNAPSHOT_LIFECYCLE, SLMUsageTransportAction.class);
262+
var slmInfoAction = new ActionHandler<>(XPackInfoFeatureAction.SNAPSHOT_LIFECYCLE, SLMInfoTransportAction.class);
261263
List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> actions = new ArrayList<>();
262-
actions.add(usageAction);
263-
actions.add(infoAction);
264+
actions.add(ilmUsageAction);
265+
actions.add(ilmInfoAction);
266+
actions.add(slmUsageAction);
267+
actions.add(slmInfoAction);
264268
if (ilmEnabled) {
265269
actions.addAll(Arrays.asList(
266270
new ActionHandler<>(PutLifecycleAction.INSTANCE, TransportPutLifecycleAction.class),
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
package org.elasticsearch.xpack.slm;
8+
9+
import org.elasticsearch.action.support.ActionFilters;
10+
import org.elasticsearch.common.inject.Inject;
11+
import org.elasticsearch.common.settings.Settings;
12+
import org.elasticsearch.license.XPackLicenseState;
13+
import org.elasticsearch.transport.TransportService;
14+
import org.elasticsearch.xpack.core.XPackField;
15+
import org.elasticsearch.xpack.core.XPackSettings;
16+
import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
17+
import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction;
18+
19+
public class SLMInfoTransportAction extends XPackInfoFeatureTransportAction {
20+
private final boolean enabled;
21+
private final XPackLicenseState licenseState;
22+
23+
@Inject
24+
public SLMInfoTransportAction(TransportService transportService, ActionFilters actionFilters,
25+
Settings settings, XPackLicenseState licenseState) {
26+
super(XPackInfoFeatureAction.SNAPSHOT_LIFECYCLE.name(), transportService, actionFilters);
27+
this.enabled = XPackSettings.SNAPSHOT_LIFECYCLE_ENABLED.get(settings);
28+
this.licenseState = licenseState;
29+
}
30+
31+
@Override
32+
public String name() {
33+
return XPackField.SNAPSHOT_LIFECYCLE;
34+
}
35+
36+
@Override
37+
public boolean available() {
38+
return licenseState.isIndexLifecycleAllowed();
39+
}
40+
41+
@Override
42+
public boolean enabled() {
43+
return enabled;
44+
}
45+
}

0 commit comments

Comments
 (0)