Skip to content

Commit cf63e5c

Browse files
committed
add support for RemoteInfo API and adds cross cluster support to IndexName
1 parent 0e69488 commit cf63e5c

File tree

13 files changed

+310
-36
lines changed

13 files changed

+310
-36
lines changed

build/Clients.Common.targets

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
<!-- File version reflects actual version number without prelease since that not allowed in its struct -->
1515
<FileVersion>$(CurrentAssemblyFileVersion)</FileVersion>
1616

17+
<DotNetCoreOnly Condition="'$(NCrunch)'=='1'">1</DotNetCoreOnly>
18+
<DotNetCoreOnly Condition="'$(NCrunch)'==''"></DotNetCoreOnly>
19+
1720
<Authors></Authors>
1821
<Company></Company>
1922
<NeutralLanguage></NeutralLanguage>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Elasticsearch.Net;
4+
using System.Threading;
5+
6+
namespace Nest
7+
{
8+
public partial interface IElasticClient
9+
{
10+
/// <summary>
11+
/// The cluster health API allows to get a very simple status on the health of the cluster.
12+
/// <para> </para><a href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/cluster-health.html">http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/cluster-health.html</a>
13+
/// </summary>
14+
/// <param name="selector">An optional descriptor to further describe the cluster health operation</param>
15+
IRemoteInfoResponse RemoteInfo(Func<RemoteInfoDescriptor, IRemoteInfoRequest> selector = null);
16+
17+
/// <inheritdoc/>
18+
IRemoteInfoResponse RemoteInfo(IRemoteInfoRequest request);
19+
20+
/// <inheritdoc/>
21+
Task<IRemoteInfoResponse> RemoteInfoAsync(Func<RemoteInfoDescriptor, IRemoteInfoRequest> selector = null, CancellationToken cancellationToken = default(CancellationToken));
22+
23+
/// <inheritdoc/>
24+
Task<IRemoteInfoResponse> RemoteInfoAsync(IRemoteInfoRequest request, CancellationToken cancellationToken = default(CancellationToken));
25+
}
26+
27+
public partial class ElasticClient
28+
{
29+
/// <inheritdoc/>
30+
public IRemoteInfoResponse RemoteInfo(Func<RemoteInfoDescriptor, IRemoteInfoRequest> selector = null) =>
31+
this.RemoteInfo(selector.InvokeOrDefault(new RemoteInfoDescriptor()));
32+
33+
/// <inheritdoc/>
34+
public IRemoteInfoResponse RemoteInfo(IRemoteInfoRequest request) =>
35+
this.Dispatcher.Dispatch<IRemoteInfoRequest, RemoteInfoRequestParameters, RemoteInfoResponse>(
36+
request,
37+
(p, d) => this.LowLevelDispatch.RemoteInfoDispatch<RemoteInfoResponse>(p)
38+
);
39+
40+
/// <inheritdoc/>
41+
public Task<IRemoteInfoResponse> RemoteInfoAsync(Func<RemoteInfoDescriptor, IRemoteInfoRequest> selector = null, CancellationToken cancellationToken = default(CancellationToken)) =>
42+
this.RemoteInfoAsync(selector.InvokeOrDefault(new RemoteInfoDescriptor()), cancellationToken);
43+
44+
/// <inheritdoc/>
45+
public Task<IRemoteInfoResponse> RemoteInfoAsync(IRemoteInfoRequest request, CancellationToken cancellationToken = default(CancellationToken)) =>
46+
this.Dispatcher.DispatchAsync<IRemoteInfoRequest, RemoteInfoRequestParameters, RemoteInfoResponse, IRemoteInfoResponse>(
47+
request,
48+
cancellationToken,
49+
(p, d, c) => this.LowLevelDispatch.RemoteInfoDispatchAsync<RemoteInfoResponse>(p, c)
50+
);
51+
}
52+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Nest
2+
{
3+
public partial interface IRemoteInfoRequest { }
4+
5+
public partial class RemoteInfoRequest { }
6+
7+
public partial class RemoteInfoDescriptor { }
8+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Collections.Generic;
2+
using Newtonsoft.Json;
3+
4+
namespace Nest
5+
{
6+
public interface IRemoteInfoResponse : IResponse
7+
{
8+
IReadOnlyDictionary<string, RemoteInfo> Remotes { get; }
9+
}
10+
11+
[JsonObject]
12+
[JsonConverter(typeof(DictionaryResponseJsonConverter<RemoteInfoResponse, string, RemoteInfo>))]
13+
public class RemoteInfoResponse : DictionaryResponseBase<string, RemoteInfo>, IRemoteInfoResponse
14+
{
15+
[JsonIgnore]
16+
public IReadOnlyDictionary<string, RemoteInfo> Remotes => Self.BackingDictionary;
17+
}
18+
19+
public class RemoteInfo
20+
{
21+
[JsonProperty("connected")]
22+
public bool Connected { get; internal set; }
23+
[JsonProperty("num_nodes_connected")]
24+
public long NumNodesConnected { get; internal set; }
25+
[JsonProperty("max_connections_per_cluster")]
26+
public int MaxConnectionsPerCluster { get; internal set; }
27+
[JsonProperty("initial_connect_timeout")]
28+
public Time InitialConnectTimeout { get; internal set; }
29+
30+
[JsonProperty("seeds")]
31+
public IReadOnlyCollection<string> Seeds { get; internal set; }= EmptyReadOnly<string>.Collection;
32+
33+
[JsonProperty("http_addresses")]
34+
public IReadOnlyCollection<string> HttpAddresses { get; internal set; }= EmptyReadOnly<string>.Collection;
35+
}
36+
}

src/Nest/CommonAbstractions/Infer/IndexName/IndexName.cs

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,33 @@ namespace Nest
88
[DebuggerDisplay("{DebugDisplay,nq}")]
99
public class IndexName : IEquatable<IndexName>, IUrlParameter
1010
{
11+
private static readonly char[] ClusterSeparator = {':'};
12+
internal string DebugDisplay => Type == null ? Name : $"{nameof(IndexName)} for typeof: {Type?.Name}";
13+
14+
//TODO 6.0 make setters private and use constructor
15+
public string Cluster { get; set; }
1116
public string Name { get; set; }
1217
public Type Type { get; set; }
1318

14-
internal string DebugDisplay => Type == null ? Name : $"{nameof(IndexName)} for typeof: {Type?.Name}";
19+
public static IndexName From<T>() => typeof(T);
20+
public static IndexName From<T>(string clusterName) => From(typeof(T), clusterName);
21+
private static IndexName From(Type t, string clusterName) => new IndexName { Type = t, Cluster = clusterName};
22+
23+
public Indices And<T>() => new Indices(new[] { this, typeof(T) });
24+
public Indices And<T>(string clusterName) => new Indices(new[] { this, From(typeof(T), clusterName) });
25+
public Indices And(IndexName index) => new Indices(new[] { this, index });
1526

16-
public static implicit operator IndexName(string typeName) => typeName.IsNullOrEmpty()
17-
? null
18-
: new IndexName { Name = typeName.Trim() };
27+
private static IndexName Parse(string indexName)
28+
{
29+
if (string.IsNullOrWhiteSpace(indexName)) return null;
30+
var tokens = indexName.Split(ClusterSeparator, 2, StringSplitOptions.RemoveEmptyEntries);
31+
return tokens.Length == 1
32+
? new IndexName { Name = tokens[0].Trim() }
33+
: new IndexName { Name = tokens[1].Trim(), Cluster = tokens[0].Trim() };
34+
}
1935

20-
public static implicit operator IndexName(Type type) => type == null
21-
? null
22-
: new IndexName { Type = type };
36+
public static implicit operator IndexName(string indexName) => Parse(indexName);
37+
public static implicit operator IndexName(Type type) => type == null ? null : new IndexName { Type = type };
2338

2439
bool IEquatable<IndexName>.Equals(IndexName other) => EqualsMarker(other);
2540

@@ -33,31 +48,33 @@ public override bool Equals(object obj)
3348

3449
public override int GetHashCode()
3550
{
36-
if (this.Name != null)
37-
return this.Name.GetHashCode();
38-
if (this.Type != null)
39-
return this.Type.GetHashCode();
40-
return 0;
51+
unchecked
52+
{
53+
var hashCode = this.Name?.GetHashCode() ?? this.Type?.GetHashCode() ?? 0;
54+
hashCode = (hashCode * 397) ^ (this.Cluster?.GetHashCode() ?? 0);
55+
return hashCode;
56+
}
4157
}
4258

4359
public override string ToString()
4460
{
4561
if (!this.Name.IsNullOrEmpty())
46-
return this.Name;
47-
if (this.Type != null)
48-
return this.Type.Name;
49-
return string.Empty;
62+
return PrefixClusterName(this.Name);
63+
return this.Type != null ? PrefixClusterName(this.Type.Name) : string.Empty;
5064
}
65+
private string PrefixClusterName(string name) => PrefixClusterName(this, name);
66+
private static string PrefixClusterName(IndexName i, string name) => i.Cluster.IsNullOrEmpty() ? name : $"{i.Cluster}:{name}";
5167

5268
public bool EqualsString(string other)
5369
{
54-
return !other.IsNullOrEmpty() && other == this.Name;
70+
return !other.IsNullOrEmpty() && other == PrefixClusterName(this.Name);
5571
}
5672

5773
public bool EqualsMarker(IndexName other)
5874
{
5975
if (!this.Name.IsNullOrEmpty() && other != null && !other.Name.IsNullOrEmpty())
60-
return EqualsString(other.Name);
76+
return EqualsString(PrefixClusterName(other,other.Name));
77+
6178
if (this.Type != null && other != null && other.Type != null)
6279
return this.GetHashCode() == other.GetHashCode();
6380
return false;
@@ -72,9 +89,5 @@ public string GetString(IConnectionConfigurationValues settings)
7289
return nestSettings.Inferrer.IndexName(this);
7390
}
7491

75-
public static IndexName From<T>() => typeof(T);
76-
77-
public Indices And<T>() => new Indices(new IndexName[] { this, typeof(T) });
78-
public Indices And(IndexName index) => new Indices(new IndexName[] { this, index });
7992
}
8093
}

src/Nest/CommonAbstractions/Infer/IndexName/IndexNameJsonConverter.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
2323

2424
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
2525
{
26-
if (reader.TokenType == JsonToken.String)
27-
{
28-
string typeName = reader.Value.ToString();
29-
return (IndexName)typeName;
30-
}
31-
return null;
26+
if (reader.TokenType != JsonToken.String) return null;
27+
var typeName = reader.Value.ToString();
28+
return (IndexName)typeName;
3229
}
3330

3431
}

src/Nest/CommonAbstractions/Infer/IndexName/IndexNameResolver.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public IndexNameResolver(IConnectionSettingsValues connectionSettings)
1717
public string Resolve(IndexName i)
1818
{
1919
if (string.IsNullOrEmpty(i?.Name))
20-
return this.Resolve(i?.Type);
20+
return PrefixClusterName(i,this.Resolve(i?.Type));
2121
ValidateIndexName(i.Name);
22-
return i.Name;
22+
return PrefixClusterName(i, i.Name);
2323
}
2424

2525
public string Resolve(Type type)
@@ -35,6 +35,7 @@ public string Resolve(Type type)
3535
ValidateIndexName(indexName);
3636
return indexName;
3737
}
38+
private static string PrefixClusterName(IndexName i, string name) => i.Cluster.IsNullOrEmpty() ? name : $"{i.Cluster}:{name}";
3839

3940
private static void ValidateIndexName(string indexName)
4041
{

src/Nest/CommonAbstractions/Static/Static.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ public static class Infer
1010
{
1111
public static IndexName Index(IndexName index) => index;
1212
public static IndexName Index<T>() => typeof(T);
13+
public static IndexName Index<T>(string clusterName) => IndexName.From<T>(clusterName);
1314

14-
public static Indices Indices<T>() => typeof(T);
15+
public static Indices Indices<T>() => typeof(T);
1516
public static Indices Indices(params IndexName[] indices) => indices;
1617
public static Indices Indices(IEnumerable<IndexName> indices) => indices.ToArray();
1718
public static Indices AllIndices = Nest.Indices.All;
@@ -48,9 +49,9 @@ public static Field Field<T>(Expression<Func<T, object>> path, double? boost = n
4849

4950
public static Field Field(PropertyInfo property, double? boost = null) => new Field(property, boost);
5051

51-
public static PropertyName Property(string property) => property;
52-
53-
public static PropertyName Property<T>(Expression<Func<T, object>> path)
52+
public static PropertyName Property(string property) => property;
53+
54+
public static PropertyName Property<T>(Expression<Func<T, object>> path)
5455
where T : class => path;
5556
}
5657
}

src/Tests/ClientConcepts/HighLevel/Inference/IndexNameInference.doc.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using Tests.Framework;
55
using Tests.Framework.MockData;
66
using Xunit;
7+
using static Tests.Framework.RoundTripper;
8+
using static Nest.Infer;
79

810
namespace Tests.ClientConcepts.HighLevel.Inference
911
{
@@ -137,5 +139,67 @@ [U] public void ArgumentExceptionBubblesOut()
137139
var client = TestClient.GetClient(s => new ConnectionSettings());
138140
var e = Assert.Throws<ArgumentException>(() => client.Search<Project>());
139141
}
142+
143+
//hide
144+
[U] public void RoundTripSerializationPreservesCluster()
145+
{
146+
Expect("cluster_one:project").WhenSerializing(Index<Project>("cluster_one"));
147+
Expect("cluster_one:project").WhenSerializing((IndexName)"cluster_one:project");
148+
149+
Expect("cluster_one:project,x").WhenSerializing(Index<Project>("cluster_one").And("x"));
150+
Expect("cluster_one:project,x:devs").WhenSerializing(Index<Project>("cluster_one").And<Developer>("x"));
151+
}
152+
153+
//hide
154+
[U] public void ImplicitConversionReadsCluster()
155+
{
156+
var i = (IndexName)"cluster_one : project ";
157+
i.Cluster.Should().Be("cluster_one");
158+
i.Name.Should().Be("project");
159+
160+
i = (IndexName)"cluster_one:project";
161+
i.Cluster.Should().Be("cluster_one");
162+
i.Name.Should().Be("project");
163+
164+
i = (IndexName)" ";
165+
i.Should().BeNull();
166+
}
167+
168+
//hide
169+
[U] public void EqualsValidation()
170+
{
171+
var clusterIndex = (IndexName)"cluster_one:p";
172+
var index = (IndexName)"p";
173+
174+
clusterIndex.Should().NotBe(index);
175+
clusterIndex.Should().Be("cluster_one:p");
176+
clusterIndex.Should().Be((IndexName)"cluster_one:p");
177+
178+
Index<Project>().Should().Be(Index<Project>());
179+
Index<Project>().Should().NotBe(Index<Project>("cluster_two"));
180+
Index<Project>("cluster_one").Should().NotBe(Index<Project>("cluster_two"));
181+
Index<Project>("cluster_one").Should().NotBe("cluster_one:project");
182+
Index<Project>().Should().NotBe(Index<Developer>());
183+
Index<Project>("cluster_one").Should().NotBe(Index<Developer>("cluster_one"));
184+
}
185+
186+
//hide
187+
[U] public void GetHashCodeValidation()
188+
{
189+
var clusterIndex = (IndexName)"cluster_one:p";
190+
var index = (IndexName)"p";
191+
192+
clusterIndex.GetHashCode().Should().NotBe(index.GetHashCode()).And.NotBe(0);
193+
clusterIndex.GetHashCode().Should().Be(((IndexName)"cluster_one:p").GetHashCode()).And.NotBe(0);
194+
clusterIndex.GetHashCode().Should().Be(((IndexName)"cluster_one:p").GetHashCode()).And.NotBe(0);
195+
196+
Index<Project>().GetHashCode().Should().Be(Index<Project>().GetHashCode()).And.NotBe(0);
197+
Index<Project>().GetHashCode().Should().NotBe(Index<Project>("cluster_two").GetHashCode()).And.NotBe(0);
198+
Index<Project>("cluster_one").GetHashCode().Should().NotBe(Index<Project>("cluster_two").GetHashCode()).And.NotBe(0);
199+
Index<Project>("cluster_one").Should().NotBe("cluster_one:project").And.NotBe(0);
200+
Index<Project>().GetHashCode().Should().NotBe(Index<Developer>().GetHashCode()).And.NotBe(0);
201+
Index<Project>("cluster_one").GetHashCode().Should().NotBe(Index<Developer>("cluster_one").GetHashCode()).And.NotBe(0);
202+
203+
}
140204
}
141205
}

0 commit comments

Comments
 (0)