Skip to content

Commit

Permalink
Feature usage actions for archive (elastic#83931)
Browse files Browse the repository at this point in the history
  • Loading branch information
ywelsch authored and tlrx committed Mar 3, 2022
1 parent d49d3cf commit 80447be
Show file tree
Hide file tree
Showing 17 changed files with 331 additions and 77 deletions.
Expand Up @@ -1233,6 +1233,11 @@
"total" : 0,
"failed" : 0
}
},
"archive" : {
"available" : false,
"enabled" : true,
"indices_count" : 0
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions docs/reference/rest-api/info.asciidoc
Expand Up @@ -81,6 +81,10 @@ Example response:
"available" : true,
"enabled" : true
},
"archive" : {
"available" : true,
"enabled" : true
},
"enrich" : {
"available" : true,
"enabled" : true
Expand Down
5 changes: 5 additions & 0 deletions docs/reference/rest-api/usage.asciidoc
Expand Up @@ -395,6 +395,11 @@ GET /_xpack/usage
"aggregate_metric" : {
"available" : true,
"enabled" : true
},
"archive" : {
"available" : true,
"enabled" : true,
"indices_count" : 0
}
}
------------------------------------------------------------
Expand Down
Expand Up @@ -10,7 +10,6 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.elasticsearch.Build;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.StepListener;
Expand Down Expand Up @@ -977,7 +976,8 @@ static void validateSnapshotRestorable(RestoreSnapshotRequest request, Repositor
+ "]"
);
}
if (skipVersionChecks(repository) == false && snapshotInfo.version().before(Version.CURRENT.minimumIndexCompatibilityVersion())) {
if (ALLOW_BWC_INDICES_SETTING.get(repository.settings()) == false
&& snapshotInfo.version().before(Version.CURRENT.minimumIndexCompatibilityVersion())) {
throw new SnapshotRestoreException(
new Snapshot(repository.name(), snapshotInfo.snapshotId()),
"the snapshot was created with Elasticsearch version ["
Expand All @@ -1001,19 +1001,6 @@ static void validateSnapshotRestorable(RestoreSnapshotRequest request, Repositor
Setting.Property.NodeScope
);

private static boolean skipVersionChecks(RepositoryMetadata repositoryMetadata) {
if (Build.CURRENT.isSnapshot()) {
return ALLOW_BWC_INDICES_SETTING.get(repositoryMetadata.settings());
} else {
if (ALLOW_BWC_INDICES_SETTING.exists(repositoryMetadata.settings())) {
throw new IllegalArgumentException(
"Repository setting [" + ALLOW_BWC_INDICES_SETTING.getKey() + "] only allowed in release builds"
);
}
return false;
}
}

public static boolean failed(SnapshotInfo snapshot, String index) {
for (SnapshotShardFailure failure : snapshot.shardFailures()) {
if (index.equals(failure.index())) {
Expand Down
Expand Up @@ -36,6 +36,7 @@
import org.elasticsearch.xpack.core.action.XPackUsageAction;
import org.elasticsearch.xpack.core.aggregatemetric.AggregateMetricFeatureSetUsage;
import org.elasticsearch.xpack.core.analytics.AnalyticsFeatureSetUsage;
import org.elasticsearch.xpack.core.archive.ArchiveFeatureSetUsage;
import org.elasticsearch.xpack.core.async.DeleteAsyncResultAction;
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata;
import org.elasticsearch.xpack.core.datastreams.DataStreamFeatureSetUsage;
Expand Down Expand Up @@ -552,7 +553,9 @@ public List<NamedWriteableRegistry.Entry> getNamedWriteables() {
// Data Streams
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.DATA_STREAMS, DataStreamFeatureSetUsage::new),
// Data Tiers
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.DATA_TIERS, DataTiersFeatureSetUsage::new)
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.DATA_TIERS, DataTiersFeatureSetUsage::new),
// Archive
new NamedWriteableRegistry.Entry(XPackFeatureSet.Usage.class, XPackField.ARCHIVE, ArchiveFeatureSetUsage::new)
)
);

Expand Down
Expand Up @@ -71,6 +71,8 @@ public final class XPackField {
public static final String AGGREGATE_METRIC = "aggregate_metric";
/** Name constant for the operator privileges feature. */
public static final String OPERATOR_PRIVILEGES = "operator_privileges";
/** Name constant for the archive feature. */
public static final String ARCHIVE = "archive";

private XPackField() {}

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

public static final List<XPackInfoFeatureAction> ALL;
static {
Expand Down Expand Up @@ -74,7 +75,8 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
DATA_STREAMS,
SEARCHABLE_SNAPSHOTS,
DATA_TIERS,
AGGREGATE_METRIC
AGGREGATE_METRIC,
ARCHIVE
)
);
ALL = Collections.unmodifiableList(actions);
Expand Down
Expand Up @@ -44,6 +44,7 @@ public class XPackUsageFeatureAction extends ActionType<XPackUsageFeatureRespons
public static final XPackUsageFeatureAction DATA_STREAMS = new XPackUsageFeatureAction(XPackField.DATA_STREAMS);
public static final XPackUsageFeatureAction DATA_TIERS = new XPackUsageFeatureAction(XPackField.DATA_TIERS);
public static final XPackUsageFeatureAction AGGREGATE_METRIC = new XPackUsageFeatureAction(XPackField.AGGREGATE_METRIC);
public static final XPackUsageFeatureAction ARCHIVE = new XPackUsageFeatureAction(XPackField.ARCHIVE);

static final List<XPackUsageFeatureAction> ALL = List.of(
AGGREGATE_METRIC,
Expand All @@ -66,7 +67,8 @@ public class XPackUsageFeatureAction extends ActionType<XPackUsageFeatureRespons
SQL,
TRANSFORM,
VOTING_ONLY,
WATCHER
WATCHER,
ARCHIVE
);

// public for testing
Expand Down
@@ -0,0 +1,73 @@
/*
* 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.archive;

import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.XPackField;

import java.io.IOException;
import java.util.Objects;

public class ArchiveFeatureSetUsage extends XPackFeatureSet.Usage {

private final int numberOfArchiveIndices;

public ArchiveFeatureSetUsage(StreamInput input) throws IOException {
super(input);
numberOfArchiveIndices = input.readVInt();
}

@Override
public Version getMinimalSupportedVersion() {
return Version.V_8_2_0;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVInt(numberOfArchiveIndices);
}

public ArchiveFeatureSetUsage(boolean available, int numberOfArchiveIndices) {
super(XPackField.ARCHIVE, available, true);
this.numberOfArchiveIndices = numberOfArchiveIndices;
}

public int getNumberOfArchiveIndices() {
return numberOfArchiveIndices;
}

@Override
protected void innerXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
super.innerXContent(builder, params);
builder.field("indices_count", numberOfArchiveIndices);
}

@Override
public int hashCode() {
return Objects.hash(available, enabled, numberOfArchiveIndices);
}

@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ArchiveFeatureSetUsage other = (ArchiveFeatureSetUsage) obj;
return available == other.available && enabled == other.enabled && numberOfArchiveIndices == other.numberOfArchiveIndices;
}

}
@@ -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.core.archive;

import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.test.AbstractWireSerializingTestCase;

import java.io.IOException;

public class ArchiveFeatureSetUsageTests extends AbstractWireSerializingTestCase<ArchiveFeatureSetUsage> {

@Override
protected ArchiveFeatureSetUsage createTestInstance() {
boolean available = randomBoolean();
return new ArchiveFeatureSetUsage(available, randomIntBetween(0, 100000));
}

@Override
protected ArchiveFeatureSetUsage mutateInstance(ArchiveFeatureSetUsage instance) throws IOException {
boolean available = instance.available();
int numArchiveIndices = instance.getNumberOfArchiveIndices();
switch (between(0, 1)) {
case 0 -> available = available == false;
case 1 -> numArchiveIndices = randomValueOtherThan(numArchiveIndices, () -> randomIntBetween(0, 100000));
default -> throw new AssertionError("Illegal randomisation branch");
}
return new ArchiveFeatureSetUsage(available, numArchiveIndices);
}

@Override
protected Writeable.Reader<ArchiveFeatureSetUsage> instanceReader() {
return ArchiveFeatureSetUsage::new;
}

}
Expand Up @@ -31,6 +31,7 @@
import org.elasticsearch.license.PostStartTrialResponse;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.RepositoryPlugin;
import org.elasticsearch.protocol.xpack.XPackUsageRequest;
import org.elasticsearch.protocol.xpack.license.DeleteLicenseRequest;
import org.elasticsearch.repositories.IndexId;
import org.elasticsearch.repositories.Repository;
Expand All @@ -42,6 +43,9 @@
import org.elasticsearch.snapshots.mockstore.MockRepository;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xcontent.NamedXContentRegistry;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureResponse;
import org.elasticsearch.xpack.core.archive.ArchiveFeatureSetUsage;
import org.junit.Before;

import java.io.IOException;
Expand All @@ -52,6 +56,7 @@
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.oneOf;

@ESIntegTestCase.ClusterScope(supportsDedicatedMasters = false, numClientNodes = 0, scope = ESIntegTestCase.Scope.TEST)
Expand Down Expand Up @@ -130,6 +135,24 @@ public void createAndRestoreArchive() throws Exception {
client().execute(PostStartTrialAction.INSTANCE, request).get();
}

public void testFeatureUsage() throws Exception {
XPackUsageFeatureResponse usage = client().execute(XPackUsageFeatureAction.ARCHIVE, new XPackUsageRequest()).get();
assertThat(usage.getUsage(), instanceOf(ArchiveFeatureSetUsage.class));
ArchiveFeatureSetUsage archiveUsage = (ArchiveFeatureSetUsage) usage.getUsage();
assertEquals(0, archiveUsage.getNumberOfArchiveIndices());

final RestoreSnapshotRequest req = new RestoreSnapshotRequest(repoName, snapshotName).indices(indexName).waitForCompletion(true);

final RestoreSnapshotResponse restoreSnapshotResponse = client().admin().cluster().restoreSnapshot(req).get();
assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0));
ensureGreen(indexName);

usage = client().execute(XPackUsageFeatureAction.ARCHIVE, new XPackUsageRequest()).get();
assertThat(usage.getUsage(), instanceOf(ArchiveFeatureSetUsage.class));
archiveUsage = (ArchiveFeatureSetUsage) usage.getUsage();
assertEquals(1, archiveUsage.getNumberOfArchiveIndices());
}

public void testFailRestoreOnInvalidLicense() throws Exception {
assertAcked(client().execute(DeleteLicenseAction.INSTANCE, new DeleteLicenseRequest()).get());
assertAcked(client().execute(PostStartBasicAction.INSTANCE, new PostStartBasicRequest()).get());
Expand Down
@@ -0,0 +1,44 @@
/*
* 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.lucene.bwc;

import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction;

import static org.elasticsearch.xpack.lucene.bwc.OldLuceneVersions.ARCHIVE_FEATURE;

public class ArchiveInfoTransportAction extends XPackInfoFeatureTransportAction {

private final XPackLicenseState licenseState;

@Inject
public ArchiveInfoTransportAction(TransportService transportService, ActionFilters actionFilters, XPackLicenseState licenseState) {
super(XPackInfoFeatureAction.ARCHIVE.name(), transportService, actionFilters);
this.licenseState = licenseState;
}

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

@Override
public boolean available() {
return ARCHIVE_FEATURE.checkWithoutTracking(licenseState);
}

@Override
public boolean enabled() {
return true;
}
}

0 comments on commit 80447be

Please sign in to comment.