org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest Maven / Gradle / Ivy
Show all versions of elasticsearch Show documentation
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.cluster.snapshots.create;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.MasterNodeRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.action.ValidateActions.addValidationError;
import static org.elasticsearch.common.Strings.EMPTY_ARRAY;
import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
import static org.elasticsearch.common.settings.Settings.readSettingsFromStream;
import static org.elasticsearch.common.settings.Settings.writeSettingsToStream;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue;
import static org.elasticsearch.snapshots.SnapshotInfo.METADATA_FIELD_INTRODUCED;
/**
* Create snapshot request
*
* The only mandatory parameter is repository name. The repository name has to satisfy the following requirements
*
* - be a non-empty string
* - must not contain whitespace (tabs or spaces)
* - must not contain comma (',')
* - must not contain hash sign ('#')
* - must not start with underscore ('-')
* - must be lowercase
* - must not contain invalid file name characters {@link org.elasticsearch.common.Strings#INVALID_FILENAME_CHARS}
*
*/
public class CreateSnapshotRequest extends MasterNodeRequest
implements IndicesRequest.Replaceable, ToXContentObject {
public static int MAXIMUM_METADATA_BYTES = 1024; // chosen arbitrarily
private String snapshot;
private String repository;
private String[] indices = EMPTY_ARRAY;
private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpen();
private boolean partial = false;
private Settings settings = EMPTY_SETTINGS;
private boolean includeGlobalState = true;
private boolean waitForCompletion;
private Map userMetadata;
public CreateSnapshotRequest() {
}
/**
* Constructs a new put repository request with the provided snapshot and repository names
*
* @param repository repository name
* @param snapshot snapshot name
*/
public CreateSnapshotRequest(String repository, String snapshot) {
this.snapshot = snapshot;
this.repository = repository;
}
public CreateSnapshotRequest(StreamInput in) throws IOException {
super(in);
snapshot = in.readString();
repository = in.readString();
indices = in.readStringArray();
indicesOptions = IndicesOptions.readIndicesOptions(in);
settings = readSettingsFromStream(in);
includeGlobalState = in.readBoolean();
waitForCompletion = in.readBoolean();
partial = in.readBoolean();
if (in.getVersion().onOrAfter(METADATA_FIELD_INTRODUCED)) {
userMetadata = in.readMap();
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(snapshot);
out.writeString(repository);
out.writeStringArray(indices);
indicesOptions.writeIndicesOptions(out);
writeSettingsToStream(settings, out);
out.writeBoolean(includeGlobalState);
out.writeBoolean(waitForCompletion);
out.writeBoolean(partial);
if (out.getVersion().onOrAfter(METADATA_FIELD_INTRODUCED)) {
out.writeMap(userMetadata);
}
}
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if (snapshot == null) {
validationException = addValidationError("snapshot is missing", validationException);
}
if (repository == null) {
validationException = addValidationError("repository is missing", validationException);
}
if (indices == null) {
validationException = addValidationError("indices is null", validationException);
} else {
for (String index : indices) {
if (index == null) {
validationException = addValidationError("index is null", validationException);
break;
}
}
}
if (indicesOptions == null) {
validationException = addValidationError("indicesOptions is null", validationException);
}
if (settings == null) {
validationException = addValidationError("settings is null", validationException);
}
final int metadataSize = metadataSize(userMetadata);
if (metadataSize > MAXIMUM_METADATA_BYTES) {
validationException = addValidationError("metadata must be smaller than 1024 bytes, but was [" + metadataSize + "]",
validationException);
}
return validationException;
}
public static int metadataSize(Map userMetadata) {
if (userMetadata == null) {
return 0;
}
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
builder.value(userMetadata);
int size = BytesReference.bytes(builder).length();
return size;
} catch (IOException e) {
// This should not be possible as we are just rendering the xcontent in memory
throw new ElasticsearchException(e);
}
}
/**
* Sets the snapshot name
*
* @param snapshot snapshot name
*/
public CreateSnapshotRequest snapshot(String snapshot) {
this.snapshot = snapshot;
return this;
}
/**
* The snapshot name
*
* @return snapshot name
*/
public String snapshot() {
return this.snapshot;
}
/**
* Sets repository name
*
* @param repository name
* @return this request
*/
public CreateSnapshotRequest repository(String repository) {
this.repository = repository;
return this;
}
/**
* Returns repository name
*
* @return repository name
*/
public String repository() {
return this.repository;
}
/**
* Sets a list of indices that should be included into the snapshot
*
* The list of indices supports multi-index syntax. For example: "+test*" ,"-test42" will index all indices with
* prefix "test" except index "test42". Aliases are supported. An empty list or {"_all"} will snapshot all open
* indices in the cluster.
*
* @return this request
*/
@Override
public CreateSnapshotRequest indices(String... indices) {
this.indices = indices;
return this;
}
/**
* Sets a list of indices that should be included into the snapshot
*
* The list of indices supports multi-index syntax. For example: "+test*" ,"-test42" will index all indices with
* prefix "test" except index "test42". Aliases are supported. An empty list or {"_all"} will snapshot all open
* indices in the cluster.
*
* @return this request
*/
public CreateSnapshotRequest indices(List indices) {
this.indices = indices.toArray(new String[indices.size()]);
return this;
}
/**
* Returns a list of indices that should be included into the snapshot
*
* @return list of indices
*/
@Override
public String[] indices() {
return indices;
}
/**
* Specifies the indices options. Like what type of requested indices to ignore. For example indices that don't exist.
*
* @return the desired behaviour regarding indices options
*/
@Override
public IndicesOptions indicesOptions() {
return indicesOptions;
}
/**
* Specifies the indices options. Like what type of requested indices to ignore. For example indices that don't exist.
*
* @param indicesOptions the desired behaviour regarding indices options
* @return this request
*/
public CreateSnapshotRequest indicesOptions(IndicesOptions indicesOptions) {
this.indicesOptions = indicesOptions;
return this;
}
/**
* Returns true if indices with unavailable shards should be be partially snapshotted.
*
* @return the desired behaviour regarding indices options
*/
public boolean partial() {
return partial;
}
/**
* Set to true to allow indices with unavailable shards to be partially snapshotted.
*
* @param partial true if indices with unavailable shards should be be partially snapshotted.
* @return this request
*/
public CreateSnapshotRequest partial(boolean partial) {
this.partial = partial;
return this;
}
/**
* If set to true the operation should wait for the snapshot completion before returning.
*
* By default, the operation will return as soon as snapshot is initialized. It can be changed by setting this
* flag to true.
*
* @param waitForCompletion true if operation should wait for the snapshot completion
* @return this request
*/
public CreateSnapshotRequest waitForCompletion(boolean waitForCompletion) {
this.waitForCompletion = waitForCompletion;
return this;
}
/**
* Returns true if the request should wait for the snapshot completion before returning
*
* @return true if the request should wait for completion
*/
public boolean waitForCompletion() {
return waitForCompletion;
}
/**
* Sets repository-specific snapshot settings.
*
* See repository documentation for more information.
*
* @param settings repository-specific snapshot settings
* @return this request
*/
public CreateSnapshotRequest settings(Settings settings) {
this.settings = settings;
return this;
}
/**
* Sets repository-specific snapshot settings.
*
* See repository documentation for more information.
*
* @param settings repository-specific snapshot settings
* @return this request
*/
public CreateSnapshotRequest settings(Settings.Builder settings) {
this.settings = settings.build();
return this;
}
/**
* Sets repository-specific snapshot settings in JSON or YAML format
*
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @param xContentType the content type of the source
* @return this request
*/
public CreateSnapshotRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets repository-specific snapshot settings.
*
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @return this request
*/
public CreateSnapshotRequest settings(Map source) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(Strings.toString(builder), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
return this;
}
/**
* Returns repository-specific snapshot settings
*
* @return repository-specific snapshot settings
*/
public Settings settings() {
return this.settings;
}
/**
* Set to true if global state should be stored as part of the snapshot
*
* @param includeGlobalState true if global state should be stored
* @return this request
*/
public CreateSnapshotRequest includeGlobalState(boolean includeGlobalState) {
this.includeGlobalState = includeGlobalState;
return this;
}
/**
* Returns true if global state should be stored as part of the snapshot
*
* @return true if global state should be stored as part of the snapshot
*/
public boolean includeGlobalState() {
return includeGlobalState;
}
public Map userMetadata() {
return userMetadata;
}
public CreateSnapshotRequest userMetadata(Map userMetadata) {
this.userMetadata = userMetadata;
return this;
}
/**
* Parses snapshot definition.
*
* @param source snapshot definition
* @return this request
*/
@SuppressWarnings("unchecked")
public CreateSnapshotRequest source(Map source) {
for (Map.Entry entry : source.entrySet()) {
String name = entry.getKey();
if (name.equals("indices")) {
if (entry.getValue() instanceof String) {
indices(Strings.splitStringByCommaToArray((String) entry.getValue()));
} else if (entry.getValue() instanceof List) {
indices((List) entry.getValue());
} else {
throw new IllegalArgumentException("malformed indices section, should be an array of strings");
}
} else if (name.equals("partial")) {
partial(nodeBooleanValue(entry.getValue(), "partial"));
} else if (name.equals("settings")) {
if (!(entry.getValue() instanceof Map)) {
throw new IllegalArgumentException("malformed settings section, should indices an inner object");
}
settings((Map) entry.getValue());
} else if (name.equals("include_global_state")) {
includeGlobalState = nodeBooleanValue(entry.getValue(), "include_global_state");
} else if (name.equals("metadata")) {
if (entry.getValue() != null && (entry.getValue() instanceof Map == false)) {
throw new IllegalArgumentException("malformed metadata, should be an object");
}
userMetadata((Map) entry.getValue());
}
}
indicesOptions(IndicesOptions.fromMap(source, indicesOptions));
return this;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("repository", repository);
builder.field("snapshot", snapshot);
builder.startArray("indices");
for (String index : indices) {
builder.value(index);
}
builder.endArray();
builder.field("partial", partial);
if (settings != null) {
builder.startObject("settings");
if (settings.isEmpty() == false) {
settings.toXContent(builder, params);
}
builder.endObject();
}
builder.field("include_global_state", includeGlobalState);
if (indicesOptions != null) {
indicesOptions.toXContent(builder, params);
}
builder.field("metadata", userMetadata);
builder.endObject();
return builder;
}
@Override
public String getDescription() {
return "snapshot [" + repository + ":" + snapshot + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CreateSnapshotRequest that = (CreateSnapshotRequest) o;
return partial == that.partial &&
includeGlobalState == that.includeGlobalState &&
waitForCompletion == that.waitForCompletion &&
Objects.equals(snapshot, that.snapshot) &&
Objects.equals(repository, that.repository) &&
Arrays.equals(indices, that.indices) &&
Objects.equals(indicesOptions, that.indicesOptions) &&
Objects.equals(settings, that.settings) &&
Objects.equals(masterNodeTimeout, that.masterNodeTimeout) &&
Objects.equals(userMetadata, that.userMetadata);
}
@Override
public int hashCode() {
int result = Objects.hash(snapshot, repository, indicesOptions, partial, settings, includeGlobalState,
waitForCompletion, userMetadata);
result = 31 * result + Arrays.hashCode(indices);
return result;
}
@Override
public String toString() {
return "CreateSnapshotRequest{" +
"snapshot='" + snapshot + '\'' +
", repository='" + repository + '\'' +
", indices=" + (indices == null ? null : Arrays.asList(indices)) +
", indicesOptions=" + indicesOptions +
", partial=" + partial +
", settings=" + settings +
", includeGlobalState=" + includeGlobalState +
", waitForCompletion=" + waitForCompletion +
", masterNodeTimeout=" + masterNodeTimeout +
", metadata=" + userMetadata +
'}';
}
}