diff --git a/src/Nest/Indices/Monitoring/IndicesShardStores/ElasticClient-IndicesShardStores.cs b/src/Nest/Indices/Monitoring/IndicesShardStores/ElasticClient-IndicesShardStores.cs new file mode 100644 index 00000000000..5273c9de181 --- /dev/null +++ b/src/Nest/Indices/Monitoring/IndicesShardStores/ElasticClient-IndicesShardStores.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading.Tasks; +using Elasticsearch.Net; + +namespace Nest +{ + public partial interface IElasticClient + { + /// + /// Indices level stats provide statistics on different operations happening on an index. The API provides statistics on + /// the index level scope (though most stats can also be retrieved using node level scope). + /// http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-stats.html + /// + /// Optionaly further describe the indices stats operation + IIndicesShardStoresResponse IndicesShardStores(Func selector = null); + + /// + IIndicesShardStoresResponse IndicesShardStores(IIndicesShardStoresRequest request); + + /// + Task IndicesShardStoresAsync(Func selector = null); + + /// + Task IndicesShardStoresAsync(IIndicesShardStoresRequest request); + + } + + public partial class ElasticClient + { + /// + public IIndicesShardStoresResponse IndicesShardStores(Func selector = null) => + this.IndicesShardStores(selector.InvokeOrDefault(new IndicesShardStoresDescriptor())); + + /// + public IIndicesShardStoresResponse IndicesShardStores(IIndicesShardStoresRequest request) => + this.Dispatcher.Dispatch( + request, + (p, d) => this.LowLevelDispatch.IndicesShardStoresDispatch(p) + ); + + /// + public Task IndicesShardStoresAsync(Func selector = null) => + this.IndicesShardStoresAsync(selector.InvokeOrDefault(new IndicesShardStoresDescriptor())); + + /// + public Task IndicesShardStoresAsync(IIndicesShardStoresRequest request) => + this.Dispatcher.DispatchAsync( + request, + (p, d) => this.LowLevelDispatch.IndicesShardStoresDispatchAsync(p) + ); + } +} diff --git a/src/Nest/Indices/Monitoring/IndicesShardStores/IndicesShardStoresRequest.cs b/src/Nest/Indices/Monitoring/IndicesShardStores/IndicesShardStoresRequest.cs new file mode 100644 index 00000000000..b8e69c86ec5 --- /dev/null +++ b/src/Nest/Indices/Monitoring/IndicesShardStores/IndicesShardStoresRequest.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; + +namespace Nest +{ + public partial interface IIndicesShardStoresRequest + { + IEnumerable Types { get; set; } + } + + public partial class IndicesShardStoresRequest + { + private IEnumerable _types; + public IEnumerable Types + { + get { return _types; } + set + { + if (value.HasAny()) this.RequestState.RequestParameters.AddQueryString("types", value); + else this.RequestState.RequestParameters.RemoveQueryString("types"); + this._types = value; + } + } + } + + [DescriptorFor("IndicesShardStores")] + public partial class IndicesShardStoresDescriptor + { + private IEnumerable _types; + IEnumerable IIndicesShardStoresRequest.Types + { + get { return _types; } + set + { + if (value.HasAny()) this.RequestState.RequestParameters.AddQueryString("types", value); + else this.RequestState.RequestParameters.RemoveQueryString("types"); + this._types = value; + } + } + + //A comma-separated list of fields for `completion` metric (supports wildcards) + public IndicesShardStoresDescriptor Types(params TypeName[] types) => + Assign(a => a.Types = types); + + } +} diff --git a/src/Nest/Indices/Monitoring/IndicesShardStores/IndicesShardStoresResponse.cs b/src/Nest/Indices/Monitoring/IndicesShardStores/IndicesShardStoresResponse.cs new file mode 100644 index 00000000000..e54d1c81a8c --- /dev/null +++ b/src/Nest/Indices/Monitoring/IndicesShardStores/IndicesShardStoresResponse.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Newtonsoft.Json; + +namespace Nest +{ + public interface IIndicesShardStoresResponse : IResponse + { + [JsonProperty(PropertyName = "indices")] + [JsonConverter(typeof(VerbatimDictionaryKeysJsonConverter))] + Dictionary Indices { get; set; } + } + + [JsonObject] + public class IndicesShardStoresResponse : ResponseBase, IIndicesShardStoresResponse + { + public Dictionary Indices { get; set; } + } + + public class IndicesShardStores + { + [JsonProperty(PropertyName = "shards")] + [JsonConverter(typeof(VerbatimDictionaryKeysJsonConverter))] + public Dictionary Shards { get; set; } + } + + public class ShardStoreWrapper + { + public IEnumerable Stores { get; set; } + } + + [JsonConverter(typeof(ShardStoreJsonConverter))] + public class ShardStore + { + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("transport_address")] + public string TransportAddress { get; set; } + + [JsonProperty("version")] + public long Version { get; set; } + + [JsonProperty("store_exeption")] + public ShardStoreException StoreException { get; set; } + + [JsonProperty("allocation")] + public ShardStoreAllocation Allocation { get; set; } + + [JsonProperty("attributes")] + [JsonConverter(typeof(VerbatimDictionaryKeysJsonConverter))] + public Dictionary Attributes { get; set; } + } + + public class ShardStoreException + { + [JsonProperty("type")] + public string Type { get; set; } + [JsonProperty("reason")] + public string Reason { get; set; } + } + + public enum ShardStoreAllocation + { + [EnumMember(Value = "primary")] + Primary, + [EnumMember(Value = "replica")] + Replica, + [EnumMember(Value = "unused")] + Unused + } +} diff --git a/src/Nest/Indices/Monitoring/IndicesShardStores/ShardStoreJsonConverter.cs b/src/Nest/Indices/Monitoring/IndicesShardStores/ShardStoreJsonConverter.cs new file mode 100644 index 00000000000..6309547406d --- /dev/null +++ b/src/Nest/Indices/Monitoring/IndicesShardStores/ShardStoreJsonConverter.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Nest +{ + internal class ShardStoreJsonConverter : JsonConverter + { + private readonly VerbatimDictionaryKeysJsonConverter _dictionaryConverter = + new VerbatimDictionaryKeysJsonConverter(); + + private readonly PropertyJsonConverter _elasticTypeConverter = new PropertyJsonConverter(); + + public override bool CanRead => true; + public override bool CanWrite => false; + public override bool CanConvert(Type objectType) => objectType == typeof(IDictionary); + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var r = new ShardStore(); + JObject o = JObject.Load(reader); + var properties = o.Properties().ToListOrNullIfEmpty(); + var id = properties.First(); + properties.AddRange(id.Value.Value().Properties()); + + r.Id = id.Name; + + foreach (var p in properties) + { + switch(p.Name) + { + case "name": + r.Name = p.Value.Value(); + break; + case "transport_address": + r.TransportAddress = p.Value.Value(); + break; + case "version": + r.Version = p.Value.Value(); + break; + case "store_exception": + r.StoreException = p.Value.ToObject(); + break; + case "allocation": + r.Allocation = p.Value.ToObject(); + break; + case "attributes": + r.Attributes = p.Value.ToObject>(); + break; + } + } + return r; + } + } +} diff --git a/src/Nest/Nest.csproj b/src/Nest/Nest.csproj index dea850154e7..cdcbf409780 100644 --- a/src/Nest/Nest.csproj +++ b/src/Nest/Nest.csproj @@ -697,6 +697,10 @@ + + + + diff --git a/src/Tests/Indices/Monitoring/IndicesShardStores/IndicesShardStoresApiTests.cs b/src/Tests/Indices/Monitoring/IndicesShardStores/IndicesShardStoresApiTests.cs new file mode 100644 index 00000000000..161318d19c0 --- /dev/null +++ b/src/Tests/Indices/Monitoring/IndicesShardStores/IndicesShardStoresApiTests.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Elasticsearch.Net; +using FluentAssertions; +using Nest; +using Tests.Framework; +using Tests.Framework.Integration; +using Xunit; + +namespace Tests.Indices.Monitoring.IndicesShardStores +{ + [Collection(IntegrationContext.OwnIndex)] + public class IndicesShardStoresApiTests : ApiIntegrationTestBase + { + public IndicesShardStoresApiTests(OwnIndexCluster cluster, EndpointUsage usage) : base(cluster, usage) { } + + private static string IndexWithUnassignedShards = "nest-" + RandomString(); + + protected override void BeforeAllCalls(IElasticClient client, IDictionary values) + { + client.CreateIndex(IndexWithUnassignedShards, s => s + .Settings(settings => settings + .NumberOfShards(1) + .NumberOfReplicas(2) + ) + ); + client.Index(new IndexRequest(IndexWithUnassignedShards) + { + Document = new { x = 1 }, + Refresh = true + }); + } + + protected override LazyResponses ClientUsage() => Calls( + fluent: (client, f) => client.IndicesShardStores(f), + fluentAsync: (client, f) => client.IndicesShardStoresAsync(f), + request: (client, r) => client.IndicesShardStores(r), + requestAsync: (client, r) => client.IndicesShardStoresAsync(r) + ); + protected override IndicesShardStoresRequest Initializer => + new IndicesShardStoresRequest(IndexWithUnassignedShards) + { + Status = new[] { "all" } + }; + protected override Func Fluent => s => + s.Index(IndexWithUnassignedShards) + .Status("all"); + + protected override bool ExpectIsValid => true; + protected override int ExpectStatusCode => 200; + protected override HttpMethod HttpMethod => HttpMethod.GET; + protected override string UrlPath => $"/{IndexWithUnassignedShards}/_shard_stores"; + + [I] public Task AssertResponse() => AssertOnAllResponses(r => + { + r.Indices.Should().NotBeEmpty(); + var indicesShardStore = r.Indices[IndexWithUnassignedShards]; + indicesShardStore.Should().NotBeNull(); + indicesShardStore.Shards.Should().NotBeEmpty().And.ContainKey("0"); + var shardStoreWrapper = indicesShardStore.Shards["0"]; + shardStoreWrapper.Stores.Should().NotBeNullOrEmpty(); + + var shardStore = shardStoreWrapper.Stores.First(); + shardStore.Id.Should().NotBeNullOrWhiteSpace(); + shardStore.Name.Should().NotBeNullOrWhiteSpace(); + shardStore.TransportAddress.Should().NotBeNullOrWhiteSpace(); + shardStore.Version.Should().BeGreaterThan(0); + shardStore.Allocation.Should().Be(ShardStoreAllocation.Primary); + }); + } +} diff --git a/src/Tests/Indices/Monitoring/IndicesShardStores/IndicesShardStoresUrlTests.cs b/src/Tests/Indices/Monitoring/IndicesShardStores/IndicesShardStoresUrlTests.cs new file mode 100644 index 00000000000..a7ccc69f001 --- /dev/null +++ b/src/Tests/Indices/Monitoring/IndicesShardStores/IndicesShardStoresUrlTests.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using Elasticsearch.Net; +using Nest; +using Tests.Framework; +using Tests.Framework.MockData; +using static Tests.Framework.UrlTester; + +namespace Tests.Indices.Monitoring.IndicesShardStores +{ + public class IndicesShardStoresUrlTests + { + [U] public async Task Urls() + { + await GET($"/_shard_stores") + .Fluent(c => c.IndicesShardStores()) + .Request(c => c.IndicesShardStores(new IndicesShardStoresRequest())) + .FluentAsync(c => c.IndicesShardStoresAsync()) + .RequestAsync(c => c.IndicesShardStoresAsync(new IndicesShardStoresRequest())) + ; + + var index = "index1,index2"; + await GET($"/index1%2Cindex2/_shard_stores") + .Fluent(c => c.IndicesShardStores(s=>s.Index(index))) + .Request(c => c.IndicesShardStores(new IndicesShardStoresRequest(index))) + .FluentAsync(c => c.IndicesShardStoresAsync(s=>s.Index(index))) + .RequestAsync(c => c.IndicesShardStoresAsync(new IndicesShardStoresRequest(index))) + ; + + } + } +} diff --git a/src/Tests/Tests.csproj b/src/Tests/Tests.csproj index 3972334d63a..87ed005a0ec 100644 --- a/src/Tests/Tests.csproj +++ b/src/Tests/Tests.csproj @@ -547,6 +547,8 @@ + +