From 8941aaf806f68b48fd55f1913927ab86143fe436 Mon Sep 17 00:00:00 2001 From: Stuart Cam Date: Tue, 16 Jul 2019 16:18:44 +1000 Subject: [PATCH] Implement CCR Follow Info API (#3927) Implement CCR Follow Info API --- .../Configuration/CodeConfiguration.cs | 4 +- ...questParameters.CrossClusterReplication.cs | 6 +++ ...cLowLevelClient.CrossClusterReplication.cs | 10 +++++ .../Descriptors.CrossClusterReplication.cs | 28 ++++++++++++++ .../ElasticClient.CrossClusterReplication.cs | 24 ++++++++++++ src/Nest/Requests.CrossClusterReplication.cs | 33 ++++++++++++++++ .../Follow/FollowInfo/FollowConfig.cs | 38 +++++++++++++++++++ .../Follow/FollowInfo/FollowInfoRequest.cs | 14 +++++++ .../Follow/FollowInfo/FollowInfoResponse.cs | 30 +++++++++++++++ .../Follow/FollowInfo/FollowerIndexStatus.cs | 15 ++++++++ .../_Generated/ApiUrlsLookup.generated.cs | 1 + .../CrossClusterReplicationFollowTests.cs | 24 ++++++++++++ 12 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowConfig.cs create mode 100644 src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoRequest.cs create mode 100644 src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoResponse.cs create mode 100644 src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowerIndexStatus.cs diff --git a/src/CodeGeneration/ApiGenerator/Configuration/CodeConfiguration.cs b/src/CodeGeneration/ApiGenerator/Configuration/CodeConfiguration.cs index 6422cc5a8ed..349d03c8162 100644 --- a/src/CodeGeneration/ApiGenerator/Configuration/CodeConfiguration.cs +++ b/src/CodeGeneration/ApiGenerator/Configuration/CodeConfiguration.cs @@ -21,9 +21,7 @@ public static class CodeConfiguration // these APIs are new and need to be mapped "ml.set_upgrade_mode.json", "ml.find_file_structure.json", - "monitoring.bulk.json", - - "ccr.follow_info.json", + "monitoring.bulk.json" }; diff --git a/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.CrossClusterReplication.cs b/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.CrossClusterReplication.cs index f3c44baa3cd..1ab65082e50 100644 --- a/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.CrossClusterReplication.cs +++ b/src/Elasticsearch.Net/Api/RequestParameters/RequestParameters.CrossClusterReplication.cs @@ -45,6 +45,12 @@ public string WaitForActiveShards } } + ///Request options for FollowInfo https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + public class FollowInfoRequestParameters : RequestParameters + { + public override HttpMethod DefaultHttpMethod => HttpMethod.GET; + } + ///Request options for FollowIndexStats https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-stats.html public class FollowIndexStatsRequestParameters : RequestParameters { diff --git a/src/Elasticsearch.Net/ElasticLowLevelClient.CrossClusterReplication.cs b/src/Elasticsearch.Net/ElasticLowLevelClient.CrossClusterReplication.cs index 1ed2ef705f3..0c1561187d9 100644 --- a/src/Elasticsearch.Net/ElasticLowLevelClient.CrossClusterReplication.cs +++ b/src/Elasticsearch.Net/ElasticLowLevelClient.CrossClusterReplication.cs @@ -65,6 +65,16 @@ public TResponse CreateFollowIndex(string index, PostData body, Creat ///Request specific configuration such as querystring parameters & request specific connection settings. public Task CreateFollowIndexAsync(string index, PostData body, CreateFollowIndexRequestParameters requestParameters = null, CancellationToken ctx = default) where TResponse : class, IElasticsearchResponse, new() => DoRequestAsync(PUT, Url($"{index:index}/_ccr/follow"), ctx, body, RequestParams(requestParameters)); + ///GET on /{index}/_ccr/info https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + ///A comma-separated list of index patterns; use `_all` to perform the operation on all indices + ///Request specific configuration such as querystring parameters & request specific connection settings. + public TResponse FollowInfo(string index, FollowInfoRequestParameters requestParameters = null) + where TResponse : class, IElasticsearchResponse, new() => DoRequest(GET, Url($"{index:index}/_ccr/info"), null, RequestParams(requestParameters)); + ///GET on /{index}/_ccr/info https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + ///A comma-separated list of index patterns; use `_all` to perform the operation on all indices + ///Request specific configuration such as querystring parameters & request specific connection settings. + public Task FollowInfoAsync(string index, FollowInfoRequestParameters requestParameters = null, CancellationToken ctx = default) + where TResponse : class, IElasticsearchResponse, new() => DoRequestAsync(GET, Url($"{index:index}/_ccr/info"), ctx, null, RequestParams(requestParameters)); ///GET on /{index}/_ccr/stats https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-stats.html ///A comma-separated list of index patterns; use `_all` to perform the operation on all indices ///Request specific configuration such as querystring parameters & request specific connection settings. diff --git a/src/Nest/Descriptors.CrossClusterReplication.cs b/src/Nest/Descriptors.CrossClusterReplication.cs index 09b6e04ad9d..106b31e165d 100644 --- a/src/Nest/Descriptors.CrossClusterReplication.cs +++ b/src/Nest/Descriptors.CrossClusterReplication.cs @@ -79,6 +79,34 @@ public CreateFollowIndexDescriptor Index() public CreateFollowIndexDescriptor WaitForActiveShards(string waitforactiveshards) => Qs("wait_for_active_shards", waitforactiveshards); } + ///descriptor for FollowInfo https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + public partial class FollowInfoDescriptor : RequestDescriptorBase, IFollowInfoRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.CrossClusterReplicationFollowInfo; + ////{index}/_ccr/info + ///this parameter is required + public FollowInfoDescriptor(Indices index): base(r => r.Required("index", index)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected FollowInfoDescriptor(): base() + { + } + + // values part of the url path + Indices IFollowInfoRequest.Index => Self.RouteValues.Get("index"); + ///A comma-separated list of index patterns; use `_all` to perform the operation on all indices + public FollowInfoDescriptor Index(Indices index) => Assign(index, (a, v) => a.RouteValues.Required("index", v)); + ///a shortcut into calling Index(typeof(TOther)) + public FollowInfoDescriptor Index() + where TOther : class => Assign(typeof(TOther), (a, v) => a.RouteValues.Required("index", (Indices)v)); + ///A shortcut into calling Index(Indices.All) + public FollowInfoDescriptor AllIndices() => Index(Indices.All); + // Request parameters + } + ///descriptor for FollowIndexStats https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-stats.html public partial class FollowIndexStatsDescriptor : RequestDescriptorBase, IFollowIndexStatsRequest { diff --git a/src/Nest/ElasticClient.CrossClusterReplication.cs b/src/Nest/ElasticClient.CrossClusterReplication.cs index ef3f81f0f12..d7ffd4a1f95 100644 --- a/src/Nest/ElasticClient.CrossClusterReplication.cs +++ b/src/Nest/ElasticClient.CrossClusterReplication.cs @@ -85,6 +85,30 @@ internal CrossClusterReplicationNamespace(ElasticClient client): base(client) /// public Task CreateFollowIndexAsync(ICreateFollowIndexRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); /// + /// GET request to the ccr.follow_info API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + /// + public FollowInfoResponse FollowInfo(Indices index, Func selector = null) => FollowInfo(selector.InvokeOrDefault(new FollowInfoDescriptor(index: index))); + /// + /// GET request to the ccr.follow_info API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + /// + public Task FollowInfoAsync(Indices index, Func selector = null, CancellationToken ct = default) => FollowInfoAsync(selector.InvokeOrDefault(new FollowInfoDescriptor(index: index)), ct); + /// + /// GET request to the ccr.follow_info API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + /// + public FollowInfoResponse FollowInfo(IFollowInfoRequest request) => DoRequest(request, request.RequestParameters); + /// + /// GET request to the ccr.follow_info API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + /// + public Task FollowInfoAsync(IFollowInfoRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); + /// /// GET request to the ccr.follow_stats API, read more about this API online: /// /// https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-stats.html diff --git a/src/Nest/Requests.CrossClusterReplication.cs b/src/Nest/Requests.CrossClusterReplication.cs index 26847920379..2bae6e07e6c 100644 --- a/src/Nest/Requests.CrossClusterReplication.cs +++ b/src/Nest/Requests.CrossClusterReplication.cs @@ -106,6 +106,39 @@ public string WaitForActiveShards } } + [InterfaceDataContract] + public partial interface IFollowInfoRequest : IRequest + { + [IgnoreDataMember] + Indices Index + { + get; + } + } + + ///Request for FollowInfo https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-follow-info.html + public partial class FollowInfoRequest : PlainRequestBase, IFollowInfoRequest + { + protected IFollowInfoRequest Self => this; + internal override ApiUrls ApiUrls => ApiUrlsLookups.CrossClusterReplicationFollowInfo; + ////{index}/_ccr/info + ///this parameter is required + public FollowInfoRequest(Indices index): base(r => r.Required("index", index)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected FollowInfoRequest(): base() + { + } + + // values part of the url path + [IgnoreDataMember] + Indices IFollowInfoRequest.Index => Self.RouteValues.Get("index"); + // Request parameters + } + [InterfaceDataContract] public partial interface IFollowIndexStatsRequest : IRequest { diff --git a/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowConfig.cs b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowConfig.cs new file mode 100644 index 00000000000..eea66b1daba --- /dev/null +++ b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowConfig.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.Serialization; + +namespace Nest +{ + public class FollowConfig + { + [DataMember(Name = "max_read_request_operation_count")] + public int MaximumReadRequestOperationCount { get; internal set; } + + [DataMember(Name = "max_read_request_size")] + public string MaximumReadRequestSize { get; internal set; } + + [DataMember(Name = "max_outstanding_read_requests")] + public int MaximumOutstandingReadRequests { get; internal set; } + + [DataMember(Name = "max_write_request_operation_count")] + public int MaximumWriteRequestOperationCount { get; internal set; } + + [DataMember(Name = "max_write_request_size")] + public string MaximumWriteRequestSize { get; internal set; } + + [DataMember(Name = "max_outstanding_write_requests")] + public int MaximumOutstandingWriteRequests { get; internal set; } + + [DataMember(Name = "max_write_buffer_count")] + public int MaximumWriteBufferCount { get; internal set; } + + [DataMember(Name = "max_write_buffer_size")] + public string MaximumWriteBufferSize { get; internal set; } + + [DataMember(Name = "max_retry_delay")] + public Time MaximumRetryDelay { get; internal set; } + + [DataMember(Name = "read_poll_timeout")] + public Time ReadPollTimeout { get; internal set; } + } +} diff --git a/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoRequest.cs b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoRequest.cs new file mode 100644 index 00000000000..79bf9eb5d2d --- /dev/null +++ b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoRequest.cs @@ -0,0 +1,14 @@ +namespace Nest +{ + /// + /// Retrieves information about all follower indices. + /// + [MapsApi("ccr.follow_info.json")] + public partial interface IFollowInfoRequest { } + + /// + public partial class FollowInfoRequest { } + + /// + public partial class FollowInfoDescriptor { } +} diff --git a/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoResponse.cs b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoResponse.cs new file mode 100644 index 00000000000..f2bdf865cf6 --- /dev/null +++ b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowInfoResponse.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Elasticsearch.Net; + +namespace Nest +{ + public class FollowInfoResponse : ResponseBase + { + [DataMember(Name = "follower_indices")] + public IReadOnlyCollection FollowerIndices { get; internal set; } = EmptyReadOnly.Collection; + } + + public class FollowerInfo + { + [DataMember(Name = "follower_index")] + public string FollowerIndex { get; internal set; } + + [DataMember(Name = "remote_cluster")] + public string RemoteCluster { get; internal set; } + + [DataMember(Name = "leader_index")] + public string LeaderIndex { get; internal set; } + + [DataMember(Name = "status")] + public FollowerIndexStatus Status { get; internal set; } + + [DataMember(Name = "parameters")] + public FollowConfig Parameters { get; internal set; } + } +} diff --git a/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowerIndexStatus.cs b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowerIndexStatus.cs new file mode 100644 index 00000000000..e59c2e74c18 --- /dev/null +++ b/src/Nest/XPack/CrossClusterReplication/Follow/FollowInfo/FollowerIndexStatus.cs @@ -0,0 +1,15 @@ +using System.Runtime.Serialization; +using Elasticsearch.Net; + +namespace Nest +{ + [StringEnum] + public enum FollowerIndexStatus + { + [EnumMember(Value = "active")] + Active, + + [EnumMember(Value = "paused")] + Paused + } +} diff --git a/src/Nest/_Generated/ApiUrlsLookup.generated.cs b/src/Nest/_Generated/ApiUrlsLookup.generated.cs index 76332697bf3..6a5f159be75 100644 --- a/src/Nest/_Generated/ApiUrlsLookup.generated.cs +++ b/src/Nest/_Generated/ApiUrlsLookup.generated.cs @@ -41,6 +41,7 @@ internal static class ApiUrlsLookups internal static ApiUrls CatThreadPool = new ApiUrls(new[]{"_cat/thread_pool", "_cat/thread_pool/{thread_pool_patterns}"}); internal static ApiUrls CrossClusterReplicationDeleteAutoFollowPattern = new ApiUrls(new[]{"_ccr/auto_follow/{name}"}); internal static ApiUrls CrossClusterReplicationCreateFollowIndex = new ApiUrls(new[]{"{index}/_ccr/follow"}); + internal static ApiUrls CrossClusterReplicationFollowInfo = new ApiUrls(new[]{"{index}/_ccr/info"}); internal static ApiUrls CrossClusterReplicationFollowIndexStats = new ApiUrls(new[]{"{index}/_ccr/stats"}); internal static ApiUrls CrossClusterReplicationForgetFollowerIndex = new ApiUrls(new[]{"{index}/_ccr/forget_follower"}); internal static ApiUrls CrossClusterReplicationGetAutoFollowPattern = new ApiUrls(new[]{"_ccr/auto_follow", "_ccr/auto_follow/{name}"}); diff --git a/src/Tests/Tests/XPack/CrossClusterReplication/CrossClusterReplicationFollowTests.cs b/src/Tests/Tests/XPack/CrossClusterReplication/CrossClusterReplicationFollowTests.cs index df45f9ba051..7489ee77dda 100644 --- a/src/Tests/Tests/XPack/CrossClusterReplication/CrossClusterReplicationFollowTests.cs +++ b/src/Tests/Tests/XPack/CrossClusterReplication/CrossClusterReplicationFollowTests.cs @@ -29,6 +29,7 @@ public class CrossClusterReplicationFollowTests : CoordinatedIntegrationTestBase private const string FollowIndexStep = nameof(FollowIndexStep); private const string FollowStatsAgainStep = nameof(FollowStatsAgainStep); private const string FollowStatsStep = nameof(FollowStatsStep); + private const string FollowInfoStep = nameof(FollowInfoStep); private const string IndexDataStep = nameof(IndexDataStep); private const string PauseFollowStep = nameof(PauseFollowStep); private const string PauseForCloseStep = nameof(PauseForCloseStep); @@ -158,6 +159,17 @@ public CrossClusterReplicationFollowTests(XPackCluster cluster, EndpointUsage us (v, c, r) => c.CrossClusterReplication.FollowIndexStatsAsync(r) ) }, + { + FollowInfoStep, u => + u.Calls( + v => new FollowInfoRequest(CopyIndex(v)), + (v, d) => d, + (v, c, f) => c.CrossClusterReplication.FollowInfo(CopyIndex(v), f), + (v, c, f) => c.CrossClusterReplication.FollowInfoAsync(CopyIndex(v), f), + (v, c, r) => c.CrossClusterReplication.FollowInfo(r), + (v, c, r) => c.CrossClusterReplication.FollowInfoAsync(r) + ) + }, { DeleteOriginalIndicesStep, u => u.Calls ( @@ -271,6 +283,18 @@ [I] public async Task FollowStatsResponse() => await Assert await Assert(FollowInfoStep, r => + { + r.IsValid.Should().BeTrue(); + r.FollowerIndices.Should().NotBeNull(); + r.FollowerIndices.Should().NotBeEmpty(); + var first = r.FollowerIndices.First(); + first.FollowerIndex.Should().NotBeNullOrWhiteSpace(); + first.RemoteCluster.Should().NotBeNullOrWhiteSpace(); + first.LeaderIndex.Should().NotBeNullOrWhiteSpace(); + first.Parameters.Should().NotBeNull(); + }); + [I] public async Task GlobalStatsResponse() => await Assert(GlobalStatsStep, r => { r.IsValid.Should().BeTrue();