Skip to content

[Backport master] Implement Clone Snapshot API #5265

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

Merged
merged 2 commits into from
Jan 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/ApiGenerator/Domain/Specification/UrlPart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ public string HighLevelTypeName
case "application":
case "repository":
case "snapshot":
case "target_snapshot":
case "user":
case "username":
case "realms":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public TimeSpan Timeout
}

///<summary>Request options for Clone <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
public class CloneRequestParameters : RequestParameters<CloneRequestParameters>
public class CloneSnapshotRequestParameters : RequestParameters<CloneSnapshotRequestParameters>
{
///<summary>Explicit operation timeout for connection to master node</summary>
public TimeSpan MasterTimeout
Expand Down
4 changes: 2 additions & 2 deletions src/Elasticsearch.Net/ElasticLowLevelClient.Snapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public Task<TResponse> CleanupRepositoryAsync<TResponse>(string repository, Clea
///<param name = "targetSnapshot">The name of the cloned snapshot to create</param>
///<param name = "body">The snapshot clone definition</param>
///<param name = "requestParameters">Request specific configuration such as querystring parameters &amp; request specific connection settings.</param>
public TResponse Clone<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneRequestParameters requestParameters = null)
public TResponse Clone<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneSnapshotRequestParameters requestParameters = null)
where TResponse : class, ITransportResponse, new() => DoRequest<TResponse>(PUT, Url($"_snapshot/{repository:repository}/{snapshot:snapshot}/_clone/{targetSnapshot:targetSnapshot}"), body, RequestParams(requestParameters));
///<summary>PUT on /_snapshot/{repository}/{snapshot}/_clone/{target_snapshot} <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
///<param name = "repository">A repository name</param>
Expand All @@ -70,7 +70,7 @@ public TResponse Clone<TResponse>(string repository, string snapshot, string tar
///<param name = "body">The snapshot clone definition</param>
///<param name = "requestParameters">Request specific configuration such as querystring parameters &amp; request specific connection settings.</param>
[MapsApi("snapshot.clone", "repository, snapshot, target_snapshot, body")]
public Task<TResponse> CloneAsync<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneRequestParameters requestParameters = null, CancellationToken ctx = default)
public Task<TResponse> CloneAsync<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneSnapshotRequestParameters requestParameters = null, CancellationToken ctx = default)
where TResponse : class, ITransportResponse, new() => DoRequestAsync<TResponse>(PUT, Url($"_snapshot/{repository:repository}/{snapshot:snapshot}/_clone/{targetSnapshot:targetSnapshot}"), ctx, body, RequestParams(requestParameters));
///<summary>PUT on /_snapshot/{repository}/{snapshot} <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
///<param name = "repository">A repository name</param>
Expand Down
31 changes: 30 additions & 1 deletion src/Nest/Descriptors.Snapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,35 @@ protected CleanupRepositoryDescriptor(): base()
public CleanupRepositoryDescriptor Timeout(Time timeout) => Qs("timeout", timeout);
}

///<summary>Descriptor for Clone <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
public partial class CloneSnapshotDescriptor : RequestDescriptorBase<CloneSnapshotDescriptor, CloneSnapshotRequestParameters, ICloneSnapshotRequest>, ICloneSnapshotRequest
{
internal override ApiUrls ApiUrls => ApiUrlsLookups.SnapshotClone;
protected override HttpMethod HttpMethod => HttpMethod.PUT;
protected override bool SupportsBody => true;
///<summary>/_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}</summary>
///<param name = "repository">this parameter is required</param>
///<param name = "snapshot">this parameter is required</param>
///<param name = "targetSnapshot">this parameter is required</param>
public CloneSnapshotDescriptor(Name repository, Name snapshot, Name targetSnapshot): base(r => r.Required("repository", repository).Required("snapshot", snapshot).Required("target_snapshot", targetSnapshot))
{
}

///<summary>Used for serialization purposes, making sure we have a parameterless constructor</summary>
[SerializationConstructor]
protected CloneSnapshotDescriptor(): base()
{
}

// values part of the url path
Name ICloneSnapshotRequest.RepositoryName => Self.RouteValues.Get<Name>("repository");
Name ICloneSnapshotRequest.Snapshot => Self.RouteValues.Get<Name>("snapshot");
Name ICloneSnapshotRequest.TargetSnapshot => Self.RouteValues.Get<Name>("target_snapshot");
// Request parameters
///<summary>Explicit operation timeout for connection to master node</summary>
public CloneSnapshotDescriptor MasterTimeout(Time mastertimeout) => Qs("master_timeout", mastertimeout);
}

///<summary>Descriptor for Snapshot <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
public partial class SnapshotDescriptor : RequestDescriptorBase<SnapshotDescriptor, SnapshotRequestParameters, ISnapshotRequest>, ISnapshotRequest
{
Expand Down Expand Up @@ -322,4 +351,4 @@ protected VerifyRepositoryDescriptor(): base()
///<summary>Explicit operation timeout</summary>
public VerifyRepositoryDescriptor Timeout(Time timeout) => Qs("timeout", timeout);
}
}
}
24 changes: 24 additions & 0 deletions src/Nest/ElasticClient.Snapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,30 @@ internal SnapshotNamespace(ElasticClient client): base(client)
/// </summary>
public Task<CleanupRepositoryResponse> CleanupRepositoryAsync(ICleanupRepositoryRequest request, CancellationToken ct = default) => DoRequestAsync<ICleanupRepositoryRequest, CleanupRepositoryResponse>(request, request.RequestParameters, ct);
/// <summary>
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html">https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</a>
/// </summary>
public CloneSnapshotResponse Clone(Name repository, Name snapshot, Name targetSnapshot, Func<CloneSnapshotDescriptor, ICloneSnapshotRequest> selector) => Clone(selector.InvokeOrDefault(new CloneSnapshotDescriptor(repository: repository, snapshot: snapshot, targetSnapshot: targetSnapshot)));
/// <summary>
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html">https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</a>
/// </summary>
public Task<CloneSnapshotResponse> CloneAsync(Name repository, Name snapshot, Name targetSnapshot, Func<CloneSnapshotDescriptor, ICloneSnapshotRequest> selector, CancellationToken ct = default) => CloneAsync(selector.InvokeOrDefault(new CloneSnapshotDescriptor(repository: repository, snapshot: snapshot, targetSnapshot: targetSnapshot)), ct);
/// <summary>
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html">https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</a>
/// </summary>
public CloneSnapshotResponse Clone(ICloneSnapshotRequest request) => DoRequest<ICloneSnapshotRequest, CloneSnapshotResponse>(request, request.RequestParameters);
/// <summary>
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html">https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</a>
/// </summary>
public Task<CloneSnapshotResponse> CloneAsync(ICloneSnapshotRequest request, CancellationToken ct = default) => DoRequestAsync<ICloneSnapshotRequest, CloneSnapshotResponse>(request, request.RequestParameters, ct);
/// <summary>
/// <c>PUT</c> request to the <c>snapshot.create</c> API, read more about this API online:
/// <para></para>
/// <a href = "https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html">https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</a>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Runtime.Serialization;

namespace Nest
{
[MapsApi("snapshot.clone.json")]
[ReadAs(typeof(CloneSnapshotRequest))]
public partial interface ICloneSnapshotRequest
{
/// <summary>
/// The indices to clone.
/// </summary>
[DataMember(Name = "indices")]
Indices Indices { get; set; }
}

public partial class CloneSnapshotRequest
{
/// <inheritdoc />
public Indices Indices { get; set; }
}

public partial class CloneSnapshotDescriptor
{
Indices ICloneSnapshotRequest.Indices { get; set; }

/// <inheritdoc cref="IRestoreRequest.Indices" />
public CloneSnapshotDescriptor Index(IndexName index) => Indices(index);

/// <inheritdoc cref="IRestoreRequest.Indices" />
public CloneSnapshotDescriptor Index<T>() where T : class => Indices(typeof(T));

/// <inheritdoc cref="IRestoreRequest.Indices" />
public CloneSnapshotDescriptor Indices(Indices indices) => Assign(indices, (a, v) => a.Indices = v);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

namespace Nest
{
public class CloneSnapshotResponse : AcknowledgedResponseBase { }
}
61 changes: 60 additions & 1 deletion src/Nest/Requests.Snapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,65 @@ public Time Timeout
}
}

[InterfaceDataContract]
public partial interface ICloneSnapshotRequest : IRequest<CloneSnapshotRequestParameters>
{
[IgnoreDataMember]
Name RepositoryName
{
get;
}

[IgnoreDataMember]
Name Snapshot
{
get;
}

[IgnoreDataMember]
Name TargetSnapshot
{
get;
}
}

///<summary>Request for Clone <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
public partial class CloneSnapshotRequest : PlainRequestBase<CloneSnapshotRequestParameters>, ICloneSnapshotRequest
{
protected ICloneSnapshotRequest Self => this;
internal override ApiUrls ApiUrls => ApiUrlsLookups.SnapshotClone;
protected override HttpMethod HttpMethod => HttpMethod.PUT;
protected override bool SupportsBody => true;
///<summary>/_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}</summary>
///<param name = "repository">this parameter is required</param>
///<param name = "snapshot">this parameter is required</param>
///<param name = "targetSnapshot">this parameter is required</param>
public CloneSnapshotRequest(Name repository, Name snapshot, Name targetSnapshot): base(r => r.Required("repository", repository).Required("snapshot", snapshot).Required("target_snapshot", targetSnapshot))
{
}

///<summary>Used for serialization purposes, making sure we have a parameterless constructor</summary>
[SerializationConstructor]
protected CloneSnapshotRequest(): base()
{
}

// values part of the url path
[IgnoreDataMember]
Name ICloneSnapshotRequest.RepositoryName => Self.RouteValues.Get<Name>("repository");
[IgnoreDataMember]
Name ICloneSnapshotRequest.Snapshot => Self.RouteValues.Get<Name>("snapshot");
[IgnoreDataMember]
Name ICloneSnapshotRequest.TargetSnapshot => Self.RouteValues.Get<Name>("target_snapshot");
// Request parameters
///<summary>Explicit operation timeout for connection to master node</summary>
public Time MasterTimeout
{
get => Q<Time>("master_timeout");
set => Q("master_timeout", value);
}
}

[InterfaceDataContract]
public partial interface ISnapshotRequest : IRequest<SnapshotRequestParameters>
{
Expand Down Expand Up @@ -567,4 +626,4 @@ public Time Timeout
set => Q("timeout", value);
}
}
}
}
1 change: 1 addition & 0 deletions src/Nest/_Generated/ApiUrlsLookup.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ internal static class ApiUrlsLookups
internal static ApiUrls SnapshotLifecycleManagementStart = new ApiUrls(new[]{"_slm/start"});
internal static ApiUrls SnapshotLifecycleManagementStop = new ApiUrls(new[]{"_slm/stop"});
internal static ApiUrls SnapshotCleanupRepository = new ApiUrls(new[]{"_snapshot/{repository}/_cleanup"});
internal static ApiUrls SnapshotClone = new ApiUrls(new[]{"_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}"});
internal static ApiUrls SnapshotSnapshot = new ApiUrls(new[]{"_snapshot/{repository}/{snapshot}"});
internal static ApiUrls SnapshotCreateRepository = new ApiUrls(new[]{"_snapshot/{repository}"});
internal static ApiUrls SnapshotDelete = new ApiUrls(new[]{"_snapshot/{repository}/{snapshot}"});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System;
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using Elastic.Transport;
using Nest;
using Tests.Core.ManagedElasticsearch.Clusters;
using Tests.Framework.EndpointTests;
using Tests.Framework.EndpointTests.TestState;

namespace Tests.Modules.SnapshotAndRestore.Snapshot.CloneSnapshot
{
[SkipVersion("<7.10.0", "APIs introduced in 7.10.0")]
public class CloneSnapshotApiTests
: ApiTestBase<WritableCluster, CloneSnapshotResponse, ICloneSnapshotRequest, CloneSnapshotDescriptor, CloneSnapshotRequest>
{
private const string Repository = "repository1";
private const string SnapshotName = "snapshot1";
private const string Target = "snapshot1-clone";

public CloneSnapshotApiTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override Func<CloneSnapshotDescriptor, ICloneSnapshotRequest> Fluent => d => d.Indices("*");
protected override HttpMethod HttpMethod => HttpMethod.PUT;
protected override CloneSnapshotRequest Initializer => new CloneSnapshotRequest(Repository, SnapshotName, Target) { Indices = "*" };

protected override object ExpectJson =>
new
{
indices = "*"
};

protected override bool SupportsDeserialization => false;

protected override string UrlPath => $"/_snapshot/{Repository}/{SnapshotName}/_clone/{Target}";

protected override LazyResponses ClientUsage() => Calls(
(client, f) => client.Snapshot.Clone(Repository, SnapshotName, Target, f),
(client, f) => client.Snapshot.CloneAsync(Repository, SnapshotName, Target, f),
(client, r) => client.Snapshot.Clone(r),
(client, r) => client.Snapshot.CloneAsync(r)
);

protected override CloneSnapshotDescriptor NewDescriptor() => new(Repository, SnapshotName, Target);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Threading.Tasks;
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
using Nest;
using Tests.Framework.EndpointTests;
using static Tests.Framework.EndpointTests.UrlTester;

namespace Tests.Modules.SnapshotAndRestore.Snapshot.CloneSnapshot
{
public class CloneSnapshotUrlTests
{
[U] public async Task Urls()
{
const string repository = "repository";
const string snapshot = "snapshot";
const string target = "snapshot-clone";

await PUT($"/_snapshot/{repository}/{snapshot}/_clone/{target}")
.Fluent(c => c.Snapshot.Clone(repository, snapshot, target, f => f))
.Request(c => c.Snapshot.Clone(new CloneSnapshotRequest(repository, snapshot, target)))
.FluentAsync(c => c.Snapshot.CloneAsync(repository, snapshot, target, f => f))
.RequestAsync(c => c.Snapshot.CloneAsync(new CloneSnapshotRequest(repository, snapshot, target)))
;
}
}
}
Loading