diff --git a/src/ApiGenerator/Configuration/CodeConfiguration.cs b/src/ApiGenerator/Configuration/CodeConfiguration.cs index b58766cf819..a101acdb672 100644 --- a/src/ApiGenerator/Configuration/CodeConfiguration.cs +++ b/src/ApiGenerator/Configuration/CodeConfiguration.cs @@ -35,7 +35,6 @@ public static class CodeConfiguration public static string[] IgnoredApisHighLevel { get; } = { - "indices.resolve_index.json", // TODO: implement "security.clear_cached_privileges.json", // TODO: implement "autoscaling.get_autoscaling_decision.json", // 7.7 experimental diff --git a/src/Nest/Descriptors.Indices.cs b/src/Nest/Descriptors.Indices.cs index c64851df3d0..b31cd322411 100644 --- a/src/Nest/Descriptors.Indices.cs +++ b/src/Nest/Descriptors.Indices.cs @@ -1194,6 +1194,29 @@ public ReloadSearchAnalyzersDescriptor Index() public ReloadSearchAnalyzersDescriptor IgnoreUnavailable(bool? ignoreunavailable = true) => Qs("ignore_unavailable", ignoreunavailable); } + ///Descriptor for Resolve https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index.html + public partial class ResolveIndexDescriptor : RequestDescriptorBase, IResolveIndexRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.IndicesResolve; + ////_resolve/index/{name} + ///this parameter is required + public ResolveIndexDescriptor(Names name): base(r => r.Required("name", name)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected ResolveIndexDescriptor(): base() + { + } + + // values part of the url path + Names IResolveIndexRequest.Name => Self.RouteValues.Get("name"); + // Request parameters + ///Whether wildcard expressions should get expanded to open or closed indices (default: open) + public ResolveIndexDescriptor ExpandWildcards(ExpandWildcards? expandwildcards) => Qs("expand_wildcards", expandwildcards); + } + ///Descriptor for Rollover https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-rollover-index.html public partial class RolloverIndexDescriptor : RequestDescriptorBase, IRolloverIndexRequest { diff --git a/src/Nest/ElasticClient.Indices.cs b/src/Nest/ElasticClient.Indices.cs index 7ad282ae207..216bef6b9d8 100644 --- a/src/Nest/ElasticClient.Indices.cs +++ b/src/Nest/ElasticClient.Indices.cs @@ -787,6 +787,30 @@ public Task PutMappingAsync(Func public Task ReloadSearchAnalyzersAsync(IReloadSearchAnalyzersRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); /// + /// GET request to the indices.resolve_index API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index.html + /// + public ResolveIndexResponse Resolve(Names name, Func selector = null) => Resolve(selector.InvokeOrDefault(new ResolveIndexDescriptor(name: name))); + /// + /// GET request to the indices.resolve_index API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index.html + /// + public Task ResolveAsync(Names name, Func selector = null, CancellationToken ct = default) => ResolveAsync(selector.InvokeOrDefault(new ResolveIndexDescriptor(name: name)), ct); + /// + /// GET request to the indices.resolve_index API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index.html + /// + public ResolveIndexResponse Resolve(IResolveIndexRequest request) => DoRequest(request, request.RequestParameters); + /// + /// GET request to the indices.resolve_index API, read more about this API online: + /// + /// https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index.html + /// + public Task ResolveAsync(IResolveIndexRequest request, CancellationToken ct = default) => DoRequestAsync(request, request.RequestParameters, ct); + /// /// POST request to the indices.rollover API, read more about this API online: /// /// https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-rollover-index.html diff --git a/src/Nest/Indices/IndexManagement/ResolveIndex/ResolveIndexRequest.cs b/src/Nest/Indices/IndexManagement/ResolveIndex/ResolveIndexRequest.cs new file mode 100644 index 00000000000..10d762c463c --- /dev/null +++ b/src/Nest/Indices/IndexManagement/ResolveIndex/ResolveIndexRequest.cs @@ -0,0 +1,25 @@ +// 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 +{ + /// + /// A request to the resolve index API + /// + [MapsApi("indices.resolve_index.json")] + [ReadAs(typeof(ResolveIndexRequest))] + public partial interface IResolveIndexRequest + { + } + + /// + public partial class ResolveIndexRequest + { + } + + /// + public partial class ResolveIndexDescriptor + { + } +} diff --git a/src/Nest/Indices/IndexManagement/ResolveIndex/ResolveIndexResponse.cs b/src/Nest/Indices/IndexManagement/ResolveIndex/ResolveIndexResponse.cs new file mode 100644 index 00000000000..17217c42453 --- /dev/null +++ b/src/Nest/Indices/IndexManagement/ResolveIndex/ResolveIndexResponse.cs @@ -0,0 +1,58 @@ +// 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.Collections.Generic; +using System.Runtime.Serialization; +using Elasticsearch.Net; + +namespace Nest +{ + public class ResolveIndexResponse : ResponseBase + { + [DataMember(Name = "indices")] + public IReadOnlyCollection Indices { get; internal set; } = EmptyReadOnly.Collection; + + [DataMember(Name = "aliases")] + public IReadOnlyCollection Aliases { get; internal set; } = EmptyReadOnly.Collection; + + [DataMember(Name = "data_streams")] + public IReadOnlyCollection DataStreams { get; internal set; } = EmptyReadOnly.Collection; + } + + public class ResolvedIndex + { + [DataMember(Name = "name")] + public string Name { get; internal set; } + + [DataMember(Name = "aliases")] + public IReadOnlyCollection Aliases { get; internal set; } + + [DataMember(Name = "attributes")] + public IReadOnlyCollection Attributes { get; internal set; } + + [DataMember(Name = "data_stream")] + public string DataStream { get; internal set; } + } + + public class ResolvedAlias + { + [DataMember(Name = "name")] + public string Name { get; internal set; } + + [DataMember(Name = "indices")] + public IReadOnlyCollection Indices { get; internal set; } + } + + public class ResolvedDataStream + { + [DataMember(Name = "name")] + public string Name { get; internal set; } + + [DataMember(Name = "backing_indices")] + public IReadOnlyCollection BackingIndices { get; internal set; } + + [DataMember(Name = "timestamp_field")] + public string TimestampField { get; internal set; } + } +} diff --git a/src/Nest/Requests.Indices.cs b/src/Nest/Requests.Indices.cs index 40c587ad275..ef8d75d6a7d 100644 --- a/src/Nest/Requests.Indices.cs +++ b/src/Nest/Requests.Indices.cs @@ -2198,6 +2198,46 @@ public bool? IgnoreUnavailable } } + [InterfaceDataContract] + public partial interface IResolveIndexRequest : IRequest + { + [IgnoreDataMember] + Names Name + { + get; + } + } + + ///Request for Resolve https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-resolve-index.html + ///Note: Experimental within the Elasticsearch server, this functionality is experimental and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but experimental features are not subject to the support SLA of official GA features. + public partial class ResolveIndexRequest : PlainRequestBase, IResolveIndexRequest + { + protected IResolveIndexRequest Self => this; + internal override ApiUrls ApiUrls => ApiUrlsLookups.IndicesResolve; + ////_resolve/index/{name} + ///this parameter is required + public ResolveIndexRequest(Names name): base(r => r.Required("name", name)) + { + } + + ///Used for serialization purposes, making sure we have a parameterless constructor + [SerializationConstructor] + protected ResolveIndexRequest(): base() + { + } + + // values part of the url path + [IgnoreDataMember] + Names IResolveIndexRequest.Name => Self.RouteValues.Get("name"); + // Request parameters + ///Whether wildcard expressions should get expanded to open or closed indices (default: open) + public ExpandWildcards? ExpandWildcards + { + get => Q("expand_wildcards"); + set => Q("expand_wildcards", value); + } + } + [InterfaceDataContract] public partial interface IRolloverIndexRequest : IRequest { diff --git a/src/Nest/_Generated/ApiUrlsLookup.generated.cs b/src/Nest/_Generated/ApiUrlsLookup.generated.cs index e6114df09e1..f77fe85b4c4 100644 --- a/src/Nest/_Generated/ApiUrlsLookup.generated.cs +++ b/src/Nest/_Generated/ApiUrlsLookup.generated.cs @@ -136,6 +136,7 @@ internal static class ApiUrlsLookups internal static ApiUrls IndicesRecoveryStatus = new ApiUrls(new[]{"_recovery", "{index}/_recovery"}); internal static ApiUrls IndicesRefresh = new ApiUrls(new[]{"_refresh", "{index}/_refresh"}); internal static ApiUrls IndicesReloadSearchAnalyzers = new ApiUrls(new[]{"{index}/_reload_search_analyzers"}); + internal static ApiUrls IndicesResolve = new ApiUrls(new[]{"_resolve/index/{name}"}); internal static ApiUrls IndicesRollover = new ApiUrls(new[]{"{alias}/_rollover", "{alias}/_rollover/{new_index}"}); internal static ApiUrls IndicesSegments = new ApiUrls(new[]{"_segments", "{index}/_segments"}); internal static ApiUrls IndicesShardStores = new ApiUrls(new[]{"_shard_stores", "{index}/_shard_stores"}); diff --git a/tests/Tests/Indices/IndexManagement/ResolveIndex/ResolveIndexApiTests.cs b/tests/Tests/Indices/IndexManagement/ResolveIndex/ResolveIndexApiTests.cs new file mode 100644 index 00000000000..1dabf5ff4c7 --- /dev/null +++ b/tests/Tests/Indices/IndexManagement/ResolveIndex/ResolveIndexApiTests.cs @@ -0,0 +1,83 @@ +// 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 System.Collections.Generic; +using System.Linq; +using Elastic.Elasticsearch.Xunit.XunitPlumbing; +using Elasticsearch.Net; +using FluentAssertions; +using Nest; +using Tests.Core.Extensions; +using Tests.Core.ManagedElasticsearch.Clusters; +using Tests.Framework.EndpointTests; +using Tests.Framework.EndpointTests.TestState; + +namespace Tests.Indices.IndexManagement.ResolveIndex +{ + [SkipVersion("<7.9.0", "resolve index introduced in 7.9.0")] + public class ResolveIndexApiTests + : ApiIntegrationTestBase + { + public ResolveIndexApiTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { } + + protected override void IntegrationSetup(IElasticClient client, CallUniqueValues values) + { + foreach (var value in values) + { + var createIndexResponse = client.Indices.Create(value.Value, c => c + .Settings(s => s + .NumberOfShards(1) + .NumberOfReplicas(0) + ) + .Aliases(a => a + .Alias(value.Value + "-alias") + ) + ); + + if (!createIndexResponse.IsValid) + throw new Exception($"exception whilst setting up integration test: {createIndexResponse.DebugInformation}"); + + var clusterResponse = client.Cluster.Health(value.Value, c => c.WaitForStatus(WaitForStatus.Green)); + + if (!clusterResponse.IsValid) + throw new Exception($"exception whilst setting up integration test: {clusterResponse.DebugInformation}"); + } + } + + protected override bool ExpectIsValid => true; + + protected override int ExpectStatusCode => 200; + + protected override Func Fluent => d => d; + + protected override HttpMethod HttpMethod => HttpMethod.GET; + + protected override ResolveIndexRequest Initializer => new ResolveIndexRequest($"{CallIsolatedValue}*"); + + protected override string UrlPath => $"/_resolve/index/{CallIsolatedValue}%2A"; + + protected override LazyResponses ClientUsage() => Calls( + (client, f) => client.Indices.Resolve($"{CallIsolatedValue}*", f), + (client, f) => client.Indices.ResolveAsync($"{CallIsolatedValue}*", f), + (client, r) => client.Indices.Resolve(r), + (client, r) => client.Indices.ResolveAsync(r) + ); + + protected override ResolveIndexDescriptor NewDescriptor() => new ResolveIndexDescriptor($"{CallIsolatedValue}*"); + + protected override void ExpectResponse(ResolveIndexResponse response) + { + response.ShouldBeValid(); + response.Indices.Should().HaveCount(1); + var resolvedIndex = response.Indices.First(); + resolvedIndex.Name.Should().Be(CallIsolatedValue); + resolvedIndex.Aliases.Should().Contain(CallIsolatedValue + "-alias"); + resolvedIndex.Attributes.Should().Contain("open"); + var resolvedAlias = response.Aliases.First(); + resolvedAlias.Name.Should().Be(CallIsolatedValue + "-alias"); + resolvedAlias.Indices.Should().Contain(CallIsolatedValue); + } + } +} diff --git a/tests/Tests/Indices/IndexManagement/ResolveIndex/ResolveIndexUrlTests.cs b/tests/Tests/Indices/IndexManagement/ResolveIndex/ResolveIndexUrlTests.cs new file mode 100644 index 00000000000..c2f064bad93 --- /dev/null +++ b/tests/Tests/Indices/IndexManagement/ResolveIndex/ResolveIndexUrlTests.cs @@ -0,0 +1,26 @@ +// 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.Indices.IndexManagement.ResolveIndex +{ + public class ResolveIndexUrlTests + { + [U] public async Task Urls() + { + var index = "index1"; + await GET($"/_resolve/index/{index}") + .Fluent(c => c.Indices.Resolve(index)) + .Request(c => c.Indices.Resolve(new ResolveIndexRequest(index))) + .FluentAsync(c => c.Indices.ResolveAsync(index)) + .RequestAsync(c => c.Indices.ResolveAsync(new ResolveIndexRequest(index))) + ; + } + } +}