Skip to content

Commit 580b181

Browse files
committed
Implement Clone Snapshot API (#5240)
Implement Clone Snapshot API - Implement new API - Remove CRUD snapshot tests and replace with coordinated tests - Move tests to IntrusiveOperationCluster
1 parent 246246b commit 580b181

File tree

13 files changed

+367
-112
lines changed

13 files changed

+367
-112
lines changed

src/ApiGenerator/Domain/Specification/UrlPart.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public string HighLevelTypeName
9595
case "application":
9696
case "repository":
9797
case "snapshot":
98+
case "target_snapshot":
9899
case "user":
99100
case "username":
100101
case "realms":

src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.Snapshot.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public TimeSpan Timeout
4444
}
4545

4646
///<summary>Request options for Clone <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
47-
public class CloneRequestParameters : RequestParameters<CloneRequestParameters>
47+
public class CloneSnapshotRequestParameters : RequestParameters<CloneSnapshotRequestParameters>
4848
{
4949
///<summary>Explicit operation timeout for connection to master node</summary>
5050
public TimeSpan MasterTimeout

src/Elasticsearch.Net/ElasticLowLevelClient.Snapshot.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public Task<TResponse> CleanupRepositoryAsync<TResponse>(string repository, Clea
6161
///<param name = "targetSnapshot">The name of the cloned snapshot to create</param>
6262
///<param name = "body">The snapshot clone definition</param>
6363
///<param name = "requestParameters">Request specific configuration such as querystring parameters &amp; request specific connection settings.</param>
64-
public TResponse Clone<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneRequestParameters requestParameters = null)
64+
public TResponse Clone<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneSnapshotRequestParameters requestParameters = null)
6565
where TResponse : class, ITransportResponse, new() => DoRequest<TResponse>(PUT, Url($"_snapshot/{repository:repository}/{snapshot:snapshot}/_clone/{targetSnapshot:targetSnapshot}"), body, RequestParams(requestParameters));
6666
///<summary>PUT on /_snapshot/{repository}/{snapshot}/_clone/{target_snapshot} <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
6767
///<param name = "repository">A repository name</param>
@@ -70,7 +70,7 @@ public TResponse Clone<TResponse>(string repository, string snapshot, string tar
7070
///<param name = "body">The snapshot clone definition</param>
7171
///<param name = "requestParameters">Request specific configuration such as querystring parameters &amp; request specific connection settings.</param>
7272
[MapsApi("snapshot.clone", "repository, snapshot, target_snapshot, body")]
73-
public Task<TResponse> CloneAsync<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneRequestParameters requestParameters = null, CancellationToken ctx = default)
73+
public Task<TResponse> CloneAsync<TResponse>(string repository, string snapshot, string targetSnapshot, PostData body, CloneSnapshotRequestParameters requestParameters = null, CancellationToken ctx = default)
7474
where TResponse : class, ITransportResponse, new() => DoRequestAsync<TResponse>(PUT, Url($"_snapshot/{repository:repository}/{snapshot:snapshot}/_clone/{targetSnapshot:targetSnapshot}"), ctx, body, RequestParams(requestParameters));
7575
///<summary>PUT on /_snapshot/{repository}/{snapshot} <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
7676
///<param name = "repository">A repository name</param>

src/Nest/Descriptors.Snapshot.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,33 @@ protected CleanupRepositoryDescriptor(): base()
5858
public CleanupRepositoryDescriptor Timeout(Time timeout) => Qs("timeout", timeout);
5959
}
6060

61+
///<summary>Descriptor for Clone <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
62+
public partial class CloneSnapshotDescriptor : RequestDescriptorBase<CloneSnapshotDescriptor, CloneSnapshotRequestParameters, ICloneSnapshotRequest>, ICloneSnapshotRequest
63+
{
64+
internal override ApiUrls ApiUrls => ApiUrlsLookups.SnapshotClone;
65+
///<summary>/_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}</summary>
66+
///<param name = "repository">this parameter is required</param>
67+
///<param name = "snapshot">this parameter is required</param>
68+
///<param name = "targetSnapshot">this parameter is required</param>
69+
public CloneSnapshotDescriptor(Name repository, Name snapshot, Name targetSnapshot): base(r => r.Required("repository", repository).Required("snapshot", snapshot).Required("target_snapshot", targetSnapshot))
70+
{
71+
}
72+
73+
///<summary>Used for serialization purposes, making sure we have a parameterless constructor</summary>
74+
[SerializationConstructor]
75+
protected CloneSnapshotDescriptor(): base()
76+
{
77+
}
78+
79+
// values part of the url path
80+
Name ICloneSnapshotRequest.RepositoryName => Self.RouteValues.Get<Name>("repository");
81+
Name ICloneSnapshotRequest.Snapshot => Self.RouteValues.Get<Name>("snapshot");
82+
Name ICloneSnapshotRequest.TargetSnapshot => Self.RouteValues.Get<Name>("target_snapshot");
83+
// Request parameters
84+
///<summary>Explicit operation timeout for connection to master node</summary>
85+
public CloneSnapshotDescriptor MasterTimeout(Time mastertimeout) => Qs("master_timeout", mastertimeout);
86+
}
87+
6188
///<summary>Descriptor for Snapshot <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
6289
public partial class SnapshotDescriptor : RequestDescriptorBase<SnapshotDescriptor, SnapshotRequestParameters, ISnapshotRequest>, ISnapshotRequest
6390
{

src/Nest/ElasticClient.Snapshot.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,30 @@ internal SnapshotNamespace(ElasticClient client): base(client)
6161
/// </summary>
6262
public Task<CleanupRepositoryResponse> CleanupRepositoryAsync(ICleanupRepositoryRequest request, CancellationToken ct = default) => DoRequestAsync<ICleanupRepositoryRequest, CleanupRepositoryResponse>(request, request.RequestParameters, ct);
6363
/// <summary>
64+
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
65+
/// <para></para>
66+
/// <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>
67+
/// </summary>
68+
public CloneSnapshotResponse Clone(Name repository, Name snapshot, Name targetSnapshot, Func<CloneSnapshotDescriptor, ICloneSnapshotRequest> selector) => Clone(selector.InvokeOrDefault(new CloneSnapshotDescriptor(repository: repository, snapshot: snapshot, targetSnapshot: targetSnapshot)));
69+
/// <summary>
70+
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
71+
/// <para></para>
72+
/// <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>
73+
/// </summary>
74+
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);
75+
/// <summary>
76+
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
77+
/// <para></para>
78+
/// <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>
79+
/// </summary>
80+
public CloneSnapshotResponse Clone(ICloneSnapshotRequest request) => DoRequest<ICloneSnapshotRequest, CloneSnapshotResponse>(request, request.RequestParameters);
81+
/// <summary>
82+
/// <c>PUT</c> request to the <c>snapshot.clone</c> API, read more about this API online:
83+
/// <para></para>
84+
/// <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>
85+
/// </summary>
86+
public Task<CloneSnapshotResponse> CloneAsync(ICloneSnapshotRequest request, CancellationToken ct = default) => DoRequestAsync<ICloneSnapshotRequest, CloneSnapshotResponse>(request, request.RequestParameters, ct);
87+
/// <summary>
6488
/// <c>PUT</c> request to the <c>snapshot.create</c> API, read more about this API online:
6589
/// <para></para>
6690
/// <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>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Runtime.Serialization;
6+
7+
namespace Nest
8+
{
9+
[MapsApi("snapshot.clone.json")]
10+
[ReadAs(typeof(CloneSnapshotRequest))]
11+
public partial interface ICloneSnapshotRequest
12+
{
13+
/// <summary>
14+
/// The indices to clone.
15+
/// </summary>
16+
[DataMember(Name = "indices")]
17+
Indices Indices { get; set; }
18+
}
19+
20+
public partial class CloneSnapshotRequest
21+
{
22+
/// <inheritdoc />
23+
public Indices Indices { get; set; }
24+
}
25+
26+
public partial class CloneSnapshotDescriptor
27+
{
28+
Indices ICloneSnapshotRequest.Indices { get; set; }
29+
30+
/// <inheritdoc cref="IRestoreRequest.Indices" />
31+
public CloneSnapshotDescriptor Index(IndexName index) => Indices(index);
32+
33+
/// <inheritdoc cref="IRestoreRequest.Indices" />
34+
public CloneSnapshotDescriptor Index<T>() where T : class => Indices(typeof(T));
35+
36+
/// <inheritdoc cref="IRestoreRequest.Indices" />
37+
public CloneSnapshotDescriptor Indices(Indices indices) => Assign(indices, (a, v) => a.Indices = v);
38+
}
39+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
namespace Nest
6+
{
7+
public class CloneSnapshotResponse : AcknowledgedResponseBase { }
8+
}

src/Nest/Requests.Snapshot.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,63 @@ public Time Timeout
8080
}
8181
}
8282

83+
[InterfaceDataContract]
84+
public partial interface ICloneSnapshotRequest : IRequest<CloneSnapshotRequestParameters>
85+
{
86+
[IgnoreDataMember]
87+
Name RepositoryName
88+
{
89+
get;
90+
}
91+
92+
[IgnoreDataMember]
93+
Name Snapshot
94+
{
95+
get;
96+
}
97+
98+
[IgnoreDataMember]
99+
Name TargetSnapshot
100+
{
101+
get;
102+
}
103+
}
104+
105+
///<summary>Request for Clone <para>https://www.elastic.co/guide/en/elasticsearch/reference/master/modules-snapshots.html</para></summary>
106+
public partial class CloneSnapshotRequest : PlainRequestBase<CloneSnapshotRequestParameters>, ICloneSnapshotRequest
107+
{
108+
protected ICloneSnapshotRequest Self => this;
109+
internal override ApiUrls ApiUrls => ApiUrlsLookups.SnapshotClone;
110+
///<summary>/_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}</summary>
111+
///<param name = "repository">this parameter is required</param>
112+
///<param name = "snapshot">this parameter is required</param>
113+
///<param name = "targetSnapshot">this parameter is required</param>
114+
public CloneSnapshotRequest(Name repository, Name snapshot, Name targetSnapshot): base(r => r.Required("repository", repository).Required("snapshot", snapshot).Required("target_snapshot", targetSnapshot))
115+
{
116+
}
117+
118+
///<summary>Used for serialization purposes, making sure we have a parameterless constructor</summary>
119+
[SerializationConstructor]
120+
protected CloneSnapshotRequest(): base()
121+
{
122+
}
123+
124+
// values part of the url path
125+
[IgnoreDataMember]
126+
Name ICloneSnapshotRequest.RepositoryName => Self.RouteValues.Get<Name>("repository");
127+
[IgnoreDataMember]
128+
Name ICloneSnapshotRequest.Snapshot => Self.RouteValues.Get<Name>("snapshot");
129+
[IgnoreDataMember]
130+
Name ICloneSnapshotRequest.TargetSnapshot => Self.RouteValues.Get<Name>("target_snapshot");
131+
// Request parameters
132+
///<summary>Explicit operation timeout for connection to master node</summary>
133+
public Time MasterTimeout
134+
{
135+
get => Q<Time>("master_timeout");
136+
set => Q("master_timeout", value);
137+
}
138+
}
139+
83140
[InterfaceDataContract]
84141
public partial interface ISnapshotRequest : IRequest<SnapshotRequestParameters>
85142
{

src/Nest/_Generated/ApiUrlsLookup.generated.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ internal static class ApiUrlsLookups
276276
internal static ApiUrls SnapshotLifecycleManagementStart = new ApiUrls(new[]{"_slm/start"});
277277
internal static ApiUrls SnapshotLifecycleManagementStop = new ApiUrls(new[]{"_slm/stop"});
278278
internal static ApiUrls SnapshotCleanupRepository = new ApiUrls(new[]{"_snapshot/{repository}/_cleanup"});
279+
internal static ApiUrls SnapshotClone = new ApiUrls(new[]{"_snapshot/{repository}/{snapshot}/_clone/{target_snapshot}"});
279280
internal static ApiUrls SnapshotSnapshot = new ApiUrls(new[]{"_snapshot/{repository}/{snapshot}"});
280281
internal static ApiUrls SnapshotCreateRepository = new ApiUrls(new[]{"_snapshot/{repository}"});
281282
internal static ApiUrls SnapshotDelete = new ApiUrls(new[]{"_snapshot/{repository}/{snapshot}"});
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System;
6+
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
7+
using Elasticsearch.Net;
8+
using Nest;
9+
using Tests.Core.ManagedElasticsearch.Clusters;
10+
using Tests.Framework.EndpointTests;
11+
using Tests.Framework.EndpointTests.TestState;
12+
13+
namespace Tests.Modules.SnapshotAndRestore.Snapshot.CloneSnapshot
14+
{
15+
[SkipVersion("<7.10.0", "APIs introduced in 7.10.0")]
16+
public class CloneSnapshotApiTests
17+
: ApiTestBase<WritableCluster, CloneSnapshotResponse, ICloneSnapshotRequest, CloneSnapshotDescriptor, CloneSnapshotRequest>
18+
{
19+
private const string Repository = "repository1";
20+
private const string SnapshotName = "snapshot1";
21+
private const string Target = "snapshot1-clone";
22+
23+
public CloneSnapshotApiTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
24+
25+
protected override Func<CloneSnapshotDescriptor, ICloneSnapshotRequest> Fluent => d => d.Indices("*");
26+
protected override HttpMethod HttpMethod => HttpMethod.PUT;
27+
protected override CloneSnapshotRequest Initializer => new CloneSnapshotRequest(Repository, SnapshotName, Target) { Indices = "*" };
28+
29+
protected override object ExpectJson =>
30+
new
31+
{
32+
indices = "*"
33+
};
34+
35+
protected override bool SupportsDeserialization => false;
36+
37+
protected override string UrlPath => $"/_snapshot/{Repository}/{SnapshotName}/_clone/{Target}";
38+
39+
protected override LazyResponses ClientUsage() => Calls(
40+
(client, f) => client.Snapshot.Clone(Repository, SnapshotName, Target, f),
41+
(client, f) => client.Snapshot.CloneAsync(Repository, SnapshotName, Target, f),
42+
(client, r) => client.Snapshot.Clone(r),
43+
(client, r) => client.Snapshot.CloneAsync(r)
44+
);
45+
46+
protected override CloneSnapshotDescriptor NewDescriptor() => new(Repository, SnapshotName, Target);
47+
}
48+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Threading.Tasks;
6+
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
7+
using Nest;
8+
using Tests.Framework.EndpointTests;
9+
using static Tests.Framework.EndpointTests.UrlTester;
10+
11+
namespace Tests.Modules.SnapshotAndRestore.Snapshot.CloneSnapshot
12+
{
13+
public class CloneSnapshotUrlTests
14+
{
15+
[U] public async Task Urls()
16+
{
17+
const string repository = "repository";
18+
const string snapshot = "snapshot";
19+
const string target = "snapshot-clone";
20+
21+
await PUT($"/_snapshot/{repository}/{snapshot}/_clone/{target}")
22+
.Fluent(c => c.Snapshot.Clone(repository, snapshot, target, f => f))
23+
.Request(c => c.Snapshot.Clone(new CloneSnapshotRequest(repository, snapshot, target)))
24+
.FluentAsync(c => c.Snapshot.CloneAsync(repository, snapshot, target, f => f))
25+
.RequestAsync(c => c.Snapshot.CloneAsync(new CloneSnapshotRequest(repository, snapshot, target)))
26+
;
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)