Skip to content

Commit 061ef69

Browse files
bleskesjaymode
authored andcommitted
HLREST: Add Clear Roles Cache API (#34187)
Adds support for the Clear Roles Cache API to the High Level Rest Client. As part of this a helper class, NodesResponseHeader, has been added that enables parsing the nodes header from responses that are node requests. Relates to #29827
1 parent bf5d9a5 commit 061ef69

File tree

9 files changed

+513
-3
lines changed

9 files changed

+513
-3
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
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;
20+
21+
import org.elasticsearch.ElasticsearchException;
22+
import org.elasticsearch.action.support.nodes.BaseNodesResponse;
23+
import org.elasticsearch.common.Nullable;
24+
import org.elasticsearch.common.ParseField;
25+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
26+
import org.elasticsearch.common.xcontent.ToXContent;
27+
import org.elasticsearch.common.xcontent.XContentBuilder;
28+
import org.elasticsearch.common.xcontent.XContentParser;
29+
import org.elasticsearch.rest.action.RestActions;
30+
31+
import java.io.IOException;
32+
import java.util.Collections;
33+
import java.util.List;
34+
import java.util.Objects;
35+
36+
/**
37+
* A utility class to parse the Nodes Header returned by
38+
* {@link RestActions#buildNodesHeader(XContentBuilder, ToXContent.Params, BaseNodesResponse)}.
39+
*/
40+
public final class NodesResponseHeader {
41+
42+
public static final ParseField TOTAL = new ParseField("total");
43+
public static final ParseField SUCCESSFUL = new ParseField("successful");
44+
public static final ParseField FAILED = new ParseField("failed");
45+
public static final ParseField FAILURES = new ParseField("failures");
46+
47+
@SuppressWarnings("unchecked")
48+
public static final ConstructingObjectParser<NodesResponseHeader, Void> PARSER =
49+
new ConstructingObjectParser<>("nodes_response_header", true,
50+
(a) -> {
51+
int i = 0;
52+
int total = (Integer) a[i++];
53+
int successful = (Integer) a[i++];
54+
int failed = (Integer) a[i++];
55+
List<ElasticsearchException> failures = (List<ElasticsearchException>) a[i++];
56+
return new NodesResponseHeader(total, successful, failed, failures);
57+
});
58+
59+
static {
60+
PARSER.declareInt(ConstructingObjectParser.constructorArg(), TOTAL);
61+
PARSER.declareInt(ConstructingObjectParser.constructorArg(), SUCCESSFUL);
62+
PARSER.declareInt(ConstructingObjectParser.constructorArg(), FAILED);
63+
PARSER.declareObjectArray(ConstructingObjectParser.optionalConstructorArg(),
64+
(p, c) -> ElasticsearchException.fromXContent(p), FAILURES);
65+
}
66+
67+
private final int total;
68+
private final int successful;
69+
private final int failed;
70+
private final List<ElasticsearchException> failures;
71+
72+
public NodesResponseHeader(int total, int successful, int failed, @Nullable List<ElasticsearchException> failures) {
73+
this.total = total;
74+
this.successful = successful;
75+
this.failed = failed;
76+
this.failures = failures == null ? Collections.emptyList() : failures;
77+
}
78+
79+
public static NodesResponseHeader fromXContent(XContentParser parser, Void context) throws IOException {
80+
return PARSER.parse(parser, context);
81+
}
82+
83+
/** the total number of nodes that the operation was carried on */
84+
public int getTotal() {
85+
return total;
86+
}
87+
88+
/** the number of nodes that the operation has failed on */
89+
public int getFailed() {
90+
return failed;
91+
}
92+
93+
/** the number of nodes that the operation was successful on */
94+
public int getSuccessful() {
95+
return successful;
96+
}
97+
98+
/**
99+
* Get the failed node exceptions.
100+
*
101+
* @return Never {@code null}. Can be empty.
102+
*/
103+
public List<ElasticsearchException> getFailures() {
104+
return failures;
105+
}
106+
107+
/**
108+
* Determine if there are any node failures in {@link #failures}.
109+
*
110+
* @return {@code true} if {@link #failures} contains at least 1 exception.
111+
*/
112+
public boolean hasFailures() {
113+
return failures.isEmpty() == false;
114+
}
115+
116+
@Override
117+
public boolean equals(Object o) {
118+
if (this == o) {
119+
return true;
120+
}
121+
if (o == null || getClass() != o.getClass()) {
122+
return false;
123+
}
124+
NodesResponseHeader that = (NodesResponseHeader) o;
125+
return total == that.total &&
126+
successful == that.successful &&
127+
failed == that.failed &&
128+
Objects.equals(failures, that.failures);
129+
}
130+
131+
@Override
132+
public int hashCode() {
133+
return Objects.hash(total, successful, failed, failures);
134+
}
135+
136+
}

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@
2020
package org.elasticsearch.client;
2121

2222
import org.elasticsearch.action.ActionListener;
23+
import org.elasticsearch.client.security.ClearRolesCacheRequest;
24+
import org.elasticsearch.client.security.ClearRolesCacheResponse;
2325
import org.elasticsearch.client.security.DeleteRoleRequest;
2426
import org.elasticsearch.client.security.DeleteRoleResponse;
2527
import org.elasticsearch.client.security.PutRoleMappingRequest;
2628
import org.elasticsearch.client.security.PutRoleMappingResponse;
2729
import org.elasticsearch.client.security.DisableUserRequest;
30+
import org.elasticsearch.client.security.EmptyResponse;
2831
import org.elasticsearch.client.security.EnableUserRequest;
2932
import org.elasticsearch.client.security.GetSslCertificatesRequest;
3033
import org.elasticsearch.client.security.GetSslCertificatesResponse;
3134
import org.elasticsearch.client.security.PutUserRequest;
3235
import org.elasticsearch.client.security.PutUserResponse;
33-
import org.elasticsearch.client.security.EmptyResponse;
3436
import org.elasticsearch.client.security.ChangePasswordRequest;
3537
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
3638
import org.elasticsearch.client.security.DeleteRoleMappingResponse;
@@ -170,6 +172,36 @@ public void disableUserAsync(DisableUserRequest request, RequestOptions options,
170172
EmptyResponse::fromXContent, listener, emptySet());
171173
}
172174

175+
/**
176+
* Clears the native roles cache for a set of roles.
177+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-role-cache.html">
178+
* the docs</a> for more.
179+
*
180+
* @param request the request with the roles for which the cache should be cleared.
181+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
182+
* @return the response from the enable user call
183+
* @throws IOException in case there is a problem sending the request or parsing back the response
184+
*/
185+
public ClearRolesCacheResponse clearRolesCache(ClearRolesCacheRequest request, RequestOptions options) throws IOException {
186+
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::clearRolesCache, options,
187+
ClearRolesCacheResponse::fromXContent, emptySet());
188+
}
189+
190+
/**
191+
* Clears the native roles cache for a set of roles asynchronously.
192+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-role-cache.html">
193+
* the docs</a> for more.
194+
*
195+
* @param request the request with the roles for which the cache should be cleared.
196+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
197+
* @param listener the listener to be notified upon request completion
198+
*/
199+
public void clearRolesCacheAsync(ClearRolesCacheRequest request, RequestOptions options,
200+
ActionListener<ClearRolesCacheResponse> listener) {
201+
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::clearRolesCache, options,
202+
ClearRolesCacheResponse::fromXContent, listener, emptySet());
203+
}
204+
173205
/**
174206
* Synchronously retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster.
175207
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-ssl.html">

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.http.client.methods.HttpDelete;
2323
import org.apache.http.client.methods.HttpPost;
2424
import org.apache.http.client.methods.HttpPut;
25+
import org.elasticsearch.client.security.ClearRolesCacheRequest;
2526
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
2627
import org.elasticsearch.client.security.DeleteRoleRequest;
2728
import org.elasticsearch.client.security.PutRoleMappingRequest;
@@ -97,6 +98,15 @@ private static Request setUserEnabled(SetUserEnabledRequest setUserEnabledReques
9798
return request;
9899
}
99100

101+
static Request clearRolesCache(ClearRolesCacheRequest disableCacheRequest) {
102+
String endpoint = new RequestConverters.EndpointBuilder()
103+
.addPathPartAsIs("_xpack/security/role")
104+
.addCommaSeparatedPathParts(disableCacheRequest.names())
105+
.addPathPart("_clear_cache")
106+
.build();
107+
return new Request(HttpPost.METHOD_NAME, endpoint);
108+
}
109+
100110
static Request deleteRoleMapping(DeleteRoleMappingRequest deleteRoleMappingRequest) {
101111
final String endpoint = new RequestConverters.EndpointBuilder()
102112
.addPathPartAsIs("_xpack/security/role_mapping")
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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.security;
21+
22+
import org.elasticsearch.client.Validatable;
23+
24+
import java.util.Arrays;
25+
26+
/**
27+
* The request used to clear the cache for native roles stored in an index.
28+
*/
29+
public final class ClearRolesCacheRequest implements Validatable {
30+
31+
private final String[] names;
32+
33+
/**
34+
* Sets the roles for which caches will be evicted. When not set all the roles will be evicted from the cache.
35+
*
36+
* @param names The role names
37+
*/
38+
public ClearRolesCacheRequest(String... names) {
39+
this.names = names;
40+
}
41+
42+
/**
43+
* @return an array of role names that will have the cache evicted or <code>null</code> if all
44+
*/
45+
public String[] names() {
46+
return names;
47+
}
48+
49+
@Override
50+
public boolean equals(Object o) {
51+
if (this == o) {
52+
return true;
53+
}
54+
if (o == null || getClass() != o.getClass()) {
55+
return false;
56+
}
57+
ClearRolesCacheRequest that = (ClearRolesCacheRequest) o;
58+
return Arrays.equals(names, that.names);
59+
}
60+
61+
@Override
62+
public int hashCode() {
63+
return Arrays.hashCode(names);
64+
}
65+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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.security;
21+
22+
import org.elasticsearch.client.NodesResponseHeader;
23+
import org.elasticsearch.common.ParseField;
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+
/**
32+
* The response object that will be returned when clearing the cache of native roles
33+
*/
34+
public final class ClearRolesCacheResponse {
35+
36+
@SuppressWarnings("unchecked")
37+
private static final ConstructingObjectParser<ClearRolesCacheResponse, Void> PARSER =
38+
new ConstructingObjectParser<>("clear_roles_cache_response", false,
39+
args -> new ClearRolesCacheResponse((List<Node>)args[0], (NodesResponseHeader) args[1], (String) args[2]));
40+
41+
static {
42+
PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> Node.PARSER.apply(p, n),
43+
new ParseField("nodes"));
44+
PARSER.declareObject(ConstructingObjectParser.constructorArg(), NodesResponseHeader::fromXContent, new ParseField("_nodes"));
45+
PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("cluster_name"));
46+
}
47+
48+
private final List<Node> nodes;
49+
private final NodesResponseHeader header;
50+
private final String clusterName;
51+
52+
public ClearRolesCacheResponse(List<Node> nodes, NodesResponseHeader header, String clusterName) {
53+
this.nodes = nodes;
54+
this.header = header;
55+
this.clusterName = Objects.requireNonNull(clusterName, "cluster name must be provided");
56+
}
57+
58+
/** returns a list of nodes in which the cache was cleared */
59+
public List<Node> getNodes() {
60+
return nodes;
61+
}
62+
63+
/**
64+
* Get the cluster name associated with all of the nodes.
65+
*
66+
* @return Never {@code null}.
67+
*/
68+
public String getClusterName() {
69+
return clusterName;
70+
}
71+
72+
/**
73+
* Gets information about the number of total, successful and failed nodes the request was run on.
74+
* Also includes exceptions if relevant.
75+
*/
76+
public NodesResponseHeader getHeader() {
77+
return header;
78+
}
79+
80+
public static class Node {
81+
82+
private static final ConstructingObjectParser<Node, String> PARSER =
83+
new ConstructingObjectParser<>("clear_roles_cache_response_node", false, (args, id) -> new Node(id, (String) args[0]));
84+
85+
static {
86+
PARSER.declareString(ConstructingObjectParser.constructorArg(), new ParseField("name"));
87+
}
88+
89+
private final String id;
90+
private final String name;
91+
92+
public Node(String id, String name) {
93+
this.id = id;
94+
this.name = name;
95+
}
96+
97+
public String getId() {
98+
return id;
99+
}
100+
101+
public String getName() {
102+
return name;
103+
}
104+
}
105+
106+
public static ClearRolesCacheResponse fromXContent(XContentParser parser) throws IOException {
107+
return PARSER.parse(parser, null);
108+
}
109+
}

0 commit comments

Comments
 (0)