Allow date math for naming newly-created snapshots (#7939)
This commit is contained in:
parent
9b47e0508b
commit
fe3e0257ae
|
@ -289,6 +289,20 @@ By setting `include_global_state` to false it's possible to prevent the cluster
|
||||||
the snapshot. By default, the entire snapshot will fail if one or more indices participating in the snapshot don't have
|
the snapshot. By default, the entire snapshot will fail if one or more indices participating in the snapshot don't have
|
||||||
all primary shards available. This behaviour can be changed by setting `partial` to `true`.
|
all primary shards available. This behaviour can be changed by setting `partial` to `true`.
|
||||||
|
|
||||||
|
Snapshot names can be automatically derived using <<date-math-index-names,date math expressions>>, similarly as when creating
|
||||||
|
new indices. Note that special characters need to be URI encoded.
|
||||||
|
|
||||||
|
For example, creating a snapshot with the current day in the name, like `snapshot-2018.05.11`, can be achieved with
|
||||||
|
the following command:
|
||||||
|
[source,js]
|
||||||
|
-----------------------------------
|
||||||
|
# PUT /_snapshot/my_backup/<snapshot-{now/d}>
|
||||||
|
PUT /_snapshot/my_backup/%3Csnapshot-%7Bnow%2Fd%7D%3E
|
||||||
|
-----------------------------------
|
||||||
|
// CONSOLE
|
||||||
|
// TEST[continued]
|
||||||
|
|
||||||
|
|
||||||
The index snapshot process is incremental. In the process of making the index snapshot Elasticsearch analyses
|
The index snapshot process is incremental. In the process of making the index snapshot Elasticsearch analyses
|
||||||
the list of the index files that are already stored in the repository and copies only files that were created or
|
the list of the index files that are already stored in the repository and copies only files that were created or
|
||||||
changed since the last snapshot. That allows multiple snapshots to be preserved in the repository in a compact form.
|
changed since the last snapshot. That allows multiple snapshots to be preserved in the repository in a compact form.
|
||||||
|
|
|
@ -71,8 +71,9 @@ public class TransportCreateSnapshotAction extends TransportMasterNodeAction<Cre
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void masterOperation(final CreateSnapshotRequest request, ClusterState state, final ActionListener<CreateSnapshotResponse> listener) {
|
protected void masterOperation(final CreateSnapshotRequest request, ClusterState state, final ActionListener<CreateSnapshotResponse> listener) {
|
||||||
|
final String snapshotName = indexNameExpressionResolver.resolveDateMathExpression(request.snapshot());
|
||||||
SnapshotsService.SnapshotRequest snapshotRequest =
|
SnapshotsService.SnapshotRequest snapshotRequest =
|
||||||
new SnapshotsService.SnapshotRequest(request.repository(), request.snapshot(), "create_snapshot [" + request.snapshot() + "]")
|
new SnapshotsService.SnapshotRequest(request.repository(), snapshotName, "create_snapshot [" + snapshotName + "]")
|
||||||
.indices(request.indices())
|
.indices(request.indices())
|
||||||
.indicesOptions(request.indicesOptions())
|
.indicesOptions(request.indicesOptions())
|
||||||
.partial(request.partial())
|
.partial(request.partial())
|
||||||
|
@ -87,7 +88,7 @@ public class TransportCreateSnapshotAction extends TransportMasterNodeAction<Cre
|
||||||
@Override
|
@Override
|
||||||
public void onSnapshotCompletion(Snapshot snapshot, SnapshotInfo snapshotInfo) {
|
public void onSnapshotCompletion(Snapshot snapshot, SnapshotInfo snapshotInfo) {
|
||||||
if (snapshot.getRepository().equals(request.repository()) &&
|
if (snapshot.getRepository().equals(request.repository()) &&
|
||||||
snapshot.getSnapshotId().getName().equals(request.snapshot())) {
|
snapshot.getSnapshotId().getName().equals(snapshotName)) {
|
||||||
listener.onResponse(new CreateSnapshotResponse(snapshotInfo));
|
listener.onResponse(new CreateSnapshotResponse(snapshotInfo));
|
||||||
snapshotsService.removeListener(this);
|
snapshotsService.removeListener(this);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +97,7 @@ public class TransportCreateSnapshotAction extends TransportMasterNodeAction<Cre
|
||||||
@Override
|
@Override
|
||||||
public void onSnapshotFailure(Snapshot snapshot, Exception e) {
|
public void onSnapshotFailure(Snapshot snapshot, Exception e) {
|
||||||
if (snapshot.getRepository().equals(request.repository()) &&
|
if (snapshot.getRepository().equals(request.repository()) &&
|
||||||
snapshot.getSnapshotId().getName().equals(request.snapshot())) {
|
snapshot.getSnapshotId().getName().equals(snapshotName)) {
|
||||||
listener.onFailure(e);
|
listener.onFailure(e);
|
||||||
snapshotsService.removeListener(this);
|
snapshotsService.removeListener(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRe
|
||||||
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
|
||||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
import org.elasticsearch.action.support.ActiveShardCount;
|
import org.elasticsearch.action.support.ActiveShardCount;
|
||||||
|
import org.elasticsearch.client.AdminClient;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
@ -41,6 +42,7 @@ import org.elasticsearch.cluster.RestoreInProgress;
|
||||||
import org.elasticsearch.cluster.SnapshotDeletionsInProgress;
|
import org.elasticsearch.cluster.SnapshotDeletionsInProgress;
|
||||||
import org.elasticsearch.cluster.SnapshotsInProgress;
|
import org.elasticsearch.cluster.SnapshotsInProgress;
|
||||||
import org.elasticsearch.cluster.health.ClusterHealthStatus;
|
import org.elasticsearch.cluster.health.ClusterHealthStatus;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
import org.elasticsearch.cluster.metadata.MetaData;
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
import org.elasticsearch.cluster.metadata.MetaDataIndexStateService;
|
import org.elasticsearch.cluster.metadata.MetaDataIndexStateService;
|
||||||
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
|
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
|
||||||
|
@ -49,6 +51,7 @@ import org.elasticsearch.common.CheckedFunction;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Priority;
|
import org.elasticsearch.common.Priority;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
@ -56,6 +59,7 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.settings.SettingsFilter;
|
import org.elasticsearch.common.settings.SettingsFilter;
|
||||||
import org.elasticsearch.common.unit.ByteSizeUnit;
|
import org.elasticsearch.common.unit.ByteSizeUnit;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.discovery.zen.ElectMasterService;
|
import org.elasticsearch.discovery.zen.ElectMasterService;
|
||||||
|
@ -68,6 +72,7 @@ import org.elasticsearch.rest.AbstractRestChannel;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
import org.elasticsearch.rest.RestResponse;
|
import org.elasticsearch.rest.RestResponse;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.rest.action.admin.cluster.RestClusterStateAction;
|
import org.elasticsearch.rest.action.admin.cluster.RestClusterStateAction;
|
||||||
import org.elasticsearch.rest.action.admin.cluster.RestGetRepositoriesAction;
|
import org.elasticsearch.rest.action.admin.cluster.RestGetRepositoriesAction;
|
||||||
import org.elasticsearch.snapshots.mockstore.MockRepository;
|
import org.elasticsearch.snapshots.mockstore.MockRepository;
|
||||||
|
@ -96,6 +101,7 @@ import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.lessThan;
|
import static org.hamcrest.Matchers.lessThan;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -981,6 +987,38 @@ public class DedicatedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTest
|
||||||
ensureYellow();
|
ensureYellow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSnapshotWithDateMath() {
|
||||||
|
final String repo = "repo";
|
||||||
|
final AdminClient admin = client().admin();
|
||||||
|
|
||||||
|
final IndexNameExpressionResolver nameExpressionResolver = new IndexNameExpressionResolver(Settings.EMPTY);
|
||||||
|
final String snapshotName = "<snapshot-{now/d}>";
|
||||||
|
|
||||||
|
logger.info("--> creating repository");
|
||||||
|
assertAcked(admin.cluster().preparePutRepository(repo).setType("fs")
|
||||||
|
.setSettings(Settings.builder().put("location", randomRepoPath())
|
||||||
|
.put("compress", randomBoolean())));
|
||||||
|
|
||||||
|
final String expression1 = nameExpressionResolver.resolveDateMathExpression(snapshotName);
|
||||||
|
logger.info("--> creating date math snapshot");
|
||||||
|
CreateSnapshotResponse snapshotResponse =
|
||||||
|
admin.cluster().prepareCreateSnapshot(repo, snapshotName)
|
||||||
|
.setIncludeGlobalState(true)
|
||||||
|
.setWaitForCompletion(true)
|
||||||
|
.get();
|
||||||
|
assertThat(snapshotResponse.status(), equalTo(RestStatus.OK));
|
||||||
|
// snapshot could be taken before or after a day rollover
|
||||||
|
final String expression2 = nameExpressionResolver.resolveDateMathExpression(snapshotName);
|
||||||
|
|
||||||
|
SnapshotsStatusResponse response = admin.cluster().prepareSnapshotStatus(repo)
|
||||||
|
.setSnapshots(Sets.newHashSet(expression1, expression2).toArray(Strings.EMPTY_ARRAY))
|
||||||
|
.setIgnoreUnavailable(true)
|
||||||
|
.get();
|
||||||
|
List<SnapshotStatus> snapshots = response.getSnapshots();
|
||||||
|
assertThat(snapshots, hasSize(1));
|
||||||
|
assertThat(snapshots.get(0).getState().completed(), equalTo(true));
|
||||||
|
}
|
||||||
|
|
||||||
public static class SnapshottableMetadata extends TestCustomMetaData {
|
public static class SnapshottableMetadata extends TestCustomMetaData {
|
||||||
public static final String TYPE = "test_snapshottable";
|
public static final String TYPE = "test_snapshottable";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue