Skip to content

Commit fa1a7c5

Browse files
AntonShuvaevmartijnvg
authored andcommitted
Add remote info to the HLRC (#49657)
Relates to #47678
1 parent d1334b8 commit fa1a7c5

File tree

23 files changed

+770
-74
lines changed

23 files changed

+770
-74
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsResponse;
2727
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
2828
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
29+
import org.elasticsearch.client.cluster.RemoteInfoRequest;
30+
import org.elasticsearch.client.cluster.RemoteInfoResponse;
2931
import org.elasticsearch.rest.RestStatus;
3032

3133
import java.io.IOException;
@@ -138,4 +140,33 @@ public Cancellable healthAsync(ClusterHealthRequest healthRequest, RequestOption
138140
return restHighLevelClient.performRequestAsyncAndParseEntity(healthRequest, ClusterRequestConverters::clusterHealth, options,
139141
ClusterHealthResponse::fromXContent, listener, singleton(RestStatus.REQUEST_TIMEOUT.getStatus()));
140142
}
143+
144+
/**
145+
* Get the remote cluster information using the Remote cluster info API.
146+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-remote-info.html"> Remote cluster info
147+
* API on elastic.co</a>
148+
* @param request the request
149+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
150+
* @return the response
151+
* @throws IOException in case there is a problem sending the request or parsing back the response
152+
*/
153+
public RemoteInfoResponse remoteInfo(RemoteInfoRequest request, RequestOptions options) throws IOException {
154+
return restHighLevelClient.performRequestAndParseEntity(request, ClusterRequestConverters::remoteInfo, options,
155+
RemoteInfoResponse::fromXContent, singleton(RestStatus.REQUEST_TIMEOUT.getStatus()));
156+
}
157+
158+
/**
159+
* Asynchronously get remote cluster information using the Remote cluster info API.
160+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-remote-info.html"> Remote cluster info
161+
* API on elastic.co</a>
162+
* @param request the request
163+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
164+
* @param listener the listener to be notified upon request completion
165+
* @return cancellable that may be used to cancel the request
166+
*/
167+
public Cancellable remoteInfoAsync(RemoteInfoRequest request, RequestOptions options,
168+
ActionListener<RemoteInfoResponse> listener) {
169+
return restHighLevelClient.performRequestAsyncAndParseEntity(request, ClusterRequestConverters::remoteInfo, options,
170+
RemoteInfoResponse::fromXContent, listener, singleton(RestStatus.REQUEST_TIMEOUT.getStatus()));
171+
}
141172
}

client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterRequestConverters.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.elasticsearch.action.admin.cluster.settings.ClusterGetSettingsRequest;
2626
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
2727
import org.elasticsearch.action.support.ActiveShardCount;
28+
import org.elasticsearch.client.cluster.RemoteInfoRequest;
2829
import org.elasticsearch.common.Strings;
2930

3031
import java.io.IOException;
@@ -76,4 +77,8 @@ static Request clusterHealth(ClusterHealthRequest healthRequest) {
7677
request.addParameters(params.asMap());
7778
return request;
7879
}
80+
81+
static Request remoteInfo(RemoteInfoRequest remoteInfoRequest) {
82+
return new Request(HttpGet.METHOD_NAME, "/_remote/info");
83+
}
7984
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.cluster;
21+
22+
import java.util.Objects;
23+
24+
public class ProxyModeInfo implements RemoteConnectionInfo.ModeInfo {
25+
static final String NAME = "proxy";
26+
static final String ADDRESS = "address";
27+
static final String NUM_SOCKETS_CONNECTED = "num_sockets_connected";
28+
static final String MAX_SOCKET_CONNECTIONS = "max_socket_connections";
29+
private final String address;
30+
private final int maxSocketConnections;
31+
private final int numSocketsConnected;
32+
33+
ProxyModeInfo(String address, int maxSocketConnections, int numSocketsConnected) {
34+
this.address = address;
35+
this.maxSocketConnections = maxSocketConnections;
36+
this.numSocketsConnected = numSocketsConnected;
37+
}
38+
39+
@Override
40+
public boolean isConnected() {
41+
return numSocketsConnected > 0;
42+
}
43+
44+
@Override
45+
public String modeName() {
46+
return NAME;
47+
}
48+
49+
public String getAddress() {
50+
return address;
51+
}
52+
53+
public int getMaxSocketConnections() {
54+
return maxSocketConnections;
55+
}
56+
57+
public int getNumSocketsConnected() {
58+
return numSocketsConnected;
59+
}
60+
61+
@Override
62+
public boolean equals(Object o) {
63+
if (this == o) return true;
64+
if (o == null || getClass() != o.getClass()) return false;
65+
ProxyModeInfo otherProxy = (ProxyModeInfo) o;
66+
return maxSocketConnections == otherProxy.maxSocketConnections &&
67+
numSocketsConnected == otherProxy.numSocketsConnected &&
68+
Objects.equals(address, otherProxy.address);
69+
}
70+
71+
@Override
72+
public int hashCode() {
73+
return Objects.hash(address, maxSocketConnections, numSocketsConnected);
74+
}
75+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.cluster;
21+
22+
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.unit.TimeValue;
24+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
25+
import org.elasticsearch.common.xcontent.XContentParser;
26+
27+
import java.io.IOException;
28+
import java.util.List;
29+
import java.util.Objects;
30+
31+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
32+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
33+
34+
/**
35+
* This class encapsulates all remote cluster information to be rendered on
36+
* {@code _remote/info} requests.
37+
*/
38+
public final class RemoteConnectionInfo {
39+
private static final String CONNECTED = "connected";
40+
private static final String MODE = "mode";
41+
private static final String INITIAL_CONNECT_TIMEOUT = "initial_connect_timeout";
42+
private static final String SKIP_UNAVAILABLE = "skip_unavailable";
43+
44+
@SuppressWarnings("unchecked")
45+
private static final ConstructingObjectParser<RemoteConnectionInfo, String> PARSER = new ConstructingObjectParser<>(
46+
"RemoteConnectionInfoObjectParser",
47+
false,
48+
(args, clusterAlias) -> {
49+
String mode = (String) args[1];
50+
ModeInfo modeInfo;
51+
if (mode.equals(ProxyModeInfo.NAME)) {
52+
modeInfo = new ProxyModeInfo((String) args[4], (int) args[5], (int) args[6]);
53+
} else if (mode.equals(SniffModeInfo.NAME)) {
54+
modeInfo = new SniffModeInfo((List<String>) args[7], (int) args[8], (int) args[9]);
55+
} else {
56+
throw new IllegalArgumentException("mode cannot be " + mode);
57+
}
58+
return new RemoteConnectionInfo(clusterAlias,
59+
modeInfo,
60+
TimeValue.parseTimeValue((String) args[2], INITIAL_CONNECT_TIMEOUT),
61+
(boolean) args[3]);
62+
});
63+
64+
static {
65+
PARSER.declareBoolean(constructorArg(), new ParseField(CONNECTED));
66+
PARSER.declareString(constructorArg(), new ParseField(MODE));
67+
PARSER.declareString(constructorArg(), new ParseField(INITIAL_CONNECT_TIMEOUT));
68+
PARSER.declareBoolean(constructorArg(), new ParseField(SKIP_UNAVAILABLE));
69+
70+
PARSER.declareString(optionalConstructorArg(), new ParseField(ProxyModeInfo.ADDRESS));
71+
PARSER.declareInt(optionalConstructorArg(), new ParseField(ProxyModeInfo.MAX_SOCKET_CONNECTIONS));
72+
PARSER.declareInt(optionalConstructorArg(), new ParseField(ProxyModeInfo.NUM_SOCKETS_CONNECTED));
73+
74+
PARSER.declareStringArray(optionalConstructorArg(), new ParseField(SniffModeInfo.SEEDS));
75+
PARSER.declareInt(optionalConstructorArg(), new ParseField(SniffModeInfo.MAX_CONNECTIONS_PER_CLUSTER));
76+
PARSER.declareInt(optionalConstructorArg(), new ParseField(SniffModeInfo.NUM_NODES_CONNECTED));
77+
}
78+
79+
final ModeInfo modeInfo;
80+
final TimeValue initialConnectionTimeout;
81+
final String clusterAlias;
82+
final boolean skipUnavailable;
83+
84+
RemoteConnectionInfo(String clusterAlias, ModeInfo modeInfo, TimeValue initialConnectionTimeout, boolean skipUnavailable) {
85+
this.clusterAlias = clusterAlias;
86+
this.modeInfo = modeInfo;
87+
this.initialConnectionTimeout = initialConnectionTimeout;
88+
this.skipUnavailable = skipUnavailable;
89+
}
90+
91+
public boolean isConnected() {
92+
return modeInfo.isConnected();
93+
}
94+
95+
public String getClusterAlias() {
96+
return clusterAlias;
97+
}
98+
99+
public ModeInfo getModeInfo() {
100+
return modeInfo;
101+
}
102+
103+
public TimeValue getInitialConnectionTimeout() {
104+
return initialConnectionTimeout;
105+
}
106+
107+
public boolean isSkipUnavailable() {
108+
return skipUnavailable;
109+
}
110+
111+
public static RemoteConnectionInfo fromXContent(XContentParser parser, String clusterAlias) throws IOException {
112+
return PARSER.parse(parser, clusterAlias);
113+
}
114+
115+
@Override
116+
public boolean equals(Object o) {
117+
if (this == o) return true;
118+
if (o == null || getClass() != o.getClass()) return false;
119+
RemoteConnectionInfo that = (RemoteConnectionInfo) o;
120+
return skipUnavailable == that.skipUnavailable &&
121+
Objects.equals(modeInfo, that.modeInfo) &&
122+
Objects.equals(initialConnectionTimeout, that.initialConnectionTimeout) &&
123+
Objects.equals(clusterAlias, that.clusterAlias);
124+
}
125+
126+
@Override
127+
public int hashCode() {
128+
return Objects.hash(modeInfo, initialConnectionTimeout, clusterAlias, skipUnavailable);
129+
}
130+
131+
public interface ModeInfo {
132+
133+
boolean isConnected();
134+
135+
String modeName();
136+
}
137+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.client.cluster;
20+
21+
import org.elasticsearch.client.Validatable;
22+
23+
/**
24+
* The request object used by the Remote cluster info API.
25+
*/
26+
public final class RemoteInfoRequest implements Validatable {
27+
28+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.client.cluster;
20+
21+
import org.elasticsearch.common.xcontent.XContentParser;
22+
23+
import java.io.IOException;
24+
import java.util.ArrayList;
25+
import java.util.Collection;
26+
import java.util.List;
27+
28+
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
29+
30+
/**
31+
* A response to _remote/info API request.
32+
*/
33+
public final class RemoteInfoResponse {
34+
35+
private List<RemoteConnectionInfo> infos;
36+
37+
RemoteInfoResponse(Collection<RemoteConnectionInfo> infos) {
38+
this.infos = List.copyOf(infos);
39+
}
40+
41+
public List<RemoteConnectionInfo> getInfos() {
42+
return infos;
43+
}
44+
45+
public static RemoteInfoResponse fromXContent(XContentParser parser) throws IOException {
46+
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);
47+
48+
List<RemoteConnectionInfo> infos = new ArrayList<>();
49+
50+
XContentParser.Token token;
51+
while ((token = parser.nextToken()) == XContentParser.Token.FIELD_NAME) {
52+
String clusterAlias = parser.currentName();
53+
RemoteConnectionInfo info = RemoteConnectionInfo.fromXContent(parser, clusterAlias);
54+
infos.add(info);
55+
}
56+
ensureExpectedToken(XContentParser.Token.END_OBJECT, token, parser::getTokenLocation);
57+
return new RemoteInfoResponse(infos);
58+
}
59+
}

0 commit comments

Comments
 (0)