Skip to content

Commit d2da68e

Browse files
authored
Deterministic response order of _security/stats (#135540)
Small quality-of-life readability improvement for humans.
1 parent 10f8536 commit d2da68e

File tree

5 files changed

+52
-3
lines changed

5 files changed

+52
-3
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCache.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
import java.io.Closeable;
4040
import java.io.IOException;
41-
import java.util.Collections;
4241
import java.util.LinkedHashMap;
4342
import java.util.List;
4443
import java.util.Map;
@@ -316,7 +315,7 @@ public Map<String, Object> usageStats() {
316315
stats.put("evictions", cacheStats.getEvictions());
317316
stats.put("hits_time_in_millis", TimeValue.nsecToMSec(hitsTimeInNanos.sum()));
318317
stats.put("misses_time_in_millis", TimeValue.nsecToMSec(missesTimeInNanos.sum()));
319-
return Collections.unmodifiableMap(stats);
318+
return stats;
320319
}
321320

322321
private static final class BitsetCacheKey {

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/action/stats/GetSecurityStatsNodeResponseTests.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99

1010
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
1111
import org.elasticsearch.common.io.stream.Writeable;
12+
import org.elasticsearch.common.util.Maps;
1213
import org.elasticsearch.test.AbstractWireSerializingTestCase;
1314

1415
import java.io.IOException;
1516
import java.util.Map;
1617
import java.util.Objects;
1718

19+
import static org.hamcrest.Matchers.equalTo;
20+
1821
public class GetSecurityStatsNodeResponseTests extends AbstractWireSerializingTestCase<GetSecurityStatsNodeResponse> {
1922

2023
@Override
@@ -46,4 +49,20 @@ protected GetSecurityStatsNodeResponse mutateInstance(GetSecurityStatsNodeRespon
4649
default -> throw new IllegalStateException("Unexpected value");
4750
};
4851
}
52+
53+
public void testRolesStatsInOrderSerialization() throws IOException {
54+
final Map<String, Object> rolesStats = Maps.newLinkedHashMapWithExpectedSize(3);
55+
rolesStats.put("one", "value");
56+
rolesStats.put("two", "value");
57+
rolesStats.put("three", "value");
58+
final GetSecurityStatsNodeResponse in = new GetSecurityStatsNodeResponse(
59+
DiscoveryNodeUtils.create(randomAlphaOfLength(10)),
60+
rolesStats
61+
);
62+
63+
final GetSecurityStatsNodeResponse out = copyInstance(in);
64+
assertThat(in, equalTo(out));
65+
66+
assertThat(out.getRolesStoreStats().keySet().toArray(new String[0]), equalTo(new String[] { "one", "two", "three" }));
67+
}
4968
}

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/DocumentSubsetBitsetCacheTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565

6666
import static org.hamcrest.Matchers.equalTo;
6767
import static org.hamcrest.Matchers.greaterThan;
68+
import static org.hamcrest.Matchers.instanceOf;
6869
import static org.hamcrest.Matchers.is;
6970
import static org.hamcrest.Matchers.lessThan;
7071
import static org.hamcrest.Matchers.not;
@@ -529,6 +530,11 @@ public void testHitsMissesAndEvictionsStats() throws Exception {
529530
assertThat(cache.usageStats(), equalTo(finalStats));
530531
}
531532

533+
public void testUsageStatsAreOrdered() {
534+
final Map<String, Object> stats = newCache(Settings.EMPTY).usageStats();
535+
assertThat("needs to be LinkedHashMap for order in transport", stats, instanceOf(LinkedHashMap.class));
536+
}
537+
532538
private void runTestOnIndex(CheckedBiConsumer<SearchExecutionContext, LeafReaderContext, Exception> body) throws Exception {
533539
runTestOnIndices(1, ctx -> {
534540
final TestIndexContext indexContext = ctx.get(0);

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStore.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.common.settings.Setting;
2323
import org.elasticsearch.common.settings.Setting.Property;
2424
import org.elasticsearch.common.settings.Settings;
25+
import org.elasticsearch.common.util.Maps;
2526
import org.elasticsearch.common.util.concurrent.ReleasableLock;
2627
import org.elasticsearch.common.util.concurrent.ThreadContext;
2728
import org.elasticsearch.common.util.set.Sets;
@@ -670,7 +671,9 @@ Iterable<ProjectScoped<RoleKey>> cachedRoles() {
670671
}
671672

672673
public Map<String, Object> usageStatsWithJustDls() {
673-
return Map.of("dls", Map.of("bit_set_cache", dlsBitsetCache.usageStats()));
674+
final Map<String, Object> usageStats = Maps.newLinkedHashMapWithExpectedSize(1);
675+
usageStats.put("dls", Map.of("bit_set_cache", dlsBitsetCache.usageStats()));
676+
return usageStats; // return LinkedHashMap for deterministic order in transport
674677
}
675678

676679
public void usageStats(ActionListener<Map<String, Object>> listener) {

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/CompositeRolesStoreTests.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
import java.util.Collections;
142142
import java.util.HashMap;
143143
import java.util.HashSet;
144+
import java.util.LinkedHashMap;
144145
import java.util.LinkedHashSet;
145146
import java.util.List;
146147
import java.util.Map;
@@ -3754,6 +3755,27 @@ public void testGetRoleDescriptorsListUsesRoleStoreToResolveRoleWithInternalRole
37543755
assertThat(future.actionGet(), equalTo(Set.of(expectedRoleDescriptor)));
37553756
}
37563757

3758+
public void testOrderedUsageStatsWithJustDls() {
3759+
final CompositeRolesStore compositeRolesStore = buildCompositeRolesStore(
3760+
SECURITY_ENABLED_SETTINGS,
3761+
null,
3762+
null,
3763+
null,
3764+
null,
3765+
null,
3766+
null,
3767+
null,
3768+
null,
3769+
null
3770+
);
3771+
3772+
assertThat(
3773+
"needs LinkedHashMap to be ordered in transport",
3774+
compositeRolesStore.usageStatsWithJustDls(),
3775+
instanceOf(LinkedHashMap.class)
3776+
);
3777+
}
3778+
37573779
private Role getRoleForRoleNames(CompositeRolesStore store, String... roleNames) {
37583780
final PlainActionFuture<Role> future = new PlainActionFuture<>();
37593781
getRoleForRoleNames(store, Set.of(roleNames), future);

0 commit comments

Comments
 (0)