/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/autoscaling/NodeAvailabilityZoneMapperTests.java

https://github.com/elasticsearch/elasticsearch · Java · 290 lines · 262 code · 22 blank · 6 comment · 12 complexity · f0af7bbe32e4027fb615e2cc0709a878 MD5 · raw file

  1. /*
  2. * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
  3. * or more contributor license agreements. Licensed under the Elastic License
  4. * 2.0; you may not use this file except in compliance with the Elastic License
  5. * 2.0.
  6. */
  7. package org.elasticsearch.xpack.ml.autoscaling;
  8. import org.elasticsearch.Version;
  9. import org.elasticsearch.cluster.node.DiscoveryNode;
  10. import org.elasticsearch.cluster.node.DiscoveryNodeRole;
  11. import org.elasticsearch.cluster.node.DiscoveryNodes;
  12. import org.elasticsearch.cluster.routing.allocation.decider.AwarenessAllocationDecider;
  13. import org.elasticsearch.common.settings.ClusterSettings;
  14. import org.elasticsearch.common.settings.Settings;
  15. import org.elasticsearch.common.transport.TransportAddress;
  16. import org.elasticsearch.test.ESTestCase;
  17. import java.net.InetAddress;
  18. import java.util.ArrayList;
  19. import java.util.Collection;
  20. import java.util.HashSet;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.OptionalInt;
  24. import java.util.Set;
  25. import static org.elasticsearch.cluster.node.DiscoveryNodeRole.DATA_ROLE;
  26. import static org.elasticsearch.cluster.node.DiscoveryNodeRole.MASTER_ROLE;
  27. import static org.elasticsearch.cluster.node.DiscoveryNodeRole.ML_ROLE;
  28. import static org.hamcrest.Matchers.aMapWithSize;
  29. import static org.hamcrest.Matchers.anEmptyMap;
  30. import static org.hamcrest.Matchers.contains;
  31. import static org.hamcrest.Matchers.containsInAnyOrder;
  32. import static org.hamcrest.Matchers.empty;
  33. import static org.hamcrest.Matchers.equalTo;
  34. import static org.hamcrest.Matchers.hasSize;
  35. import static org.hamcrest.Matchers.is;
  36. public class NodeAvailabilityZoneMapperTests extends ESTestCase {
  37. public void testBeforeClusterReady() {
  38. Settings settings = Settings.builder()
  39. .putList(
  40. AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(),
  41. List.of("region", "logical_availability_zone")
  42. )
  43. .build();
  44. ClusterSettings clusterSettings = new ClusterSettings(
  45. settings,
  46. Set.of(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING)
  47. );
  48. NodeAvailabilityZoneMapper nodeAvailabilityZoneMapper = new NodeAvailabilityZoneMapper(settings, clusterSettings);
  49. assertThat(nodeAvailabilityZoneMapper.getAwarenessAttributes(), equalTo(List.of("region", "logical_availability_zone")));
  50. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone(), anEmptyMap());
  51. assertThat(nodeAvailabilityZoneMapper.getNumAvailabilityZones(), is(OptionalInt.empty()));
  52. }
  53. public void testAvailabilityZonesNotConfiguredMultiRoleNodes() {
  54. Settings settings = Settings.EMPTY;
  55. ClusterSettings clusterSettings = new ClusterSettings(
  56. settings,
  57. Set.of(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING)
  58. );
  59. DiscoveryNodes discoveryNodes = DiscoveryNodes.builder()
  60. .add(
  61. new DiscoveryNode(
  62. "node-1",
  63. new TransportAddress(InetAddress.getLoopbackAddress(), 9300),
  64. Map.of(),
  65. Set.of(MASTER_ROLE, DATA_ROLE, ML_ROLE),
  66. Version.CURRENT
  67. )
  68. )
  69. .add(
  70. new DiscoveryNode(
  71. "node-2",
  72. new TransportAddress(InetAddress.getLoopbackAddress(), 9301),
  73. Map.of(),
  74. Set.of(MASTER_ROLE, DATA_ROLE, ML_ROLE),
  75. Version.CURRENT
  76. )
  77. )
  78. .build();
  79. NodeAvailabilityZoneMapper nodeAvailabilityZoneMapper = new NodeAvailabilityZoneMapper(settings, clusterSettings, discoveryNodes);
  80. assertThat(nodeAvailabilityZoneMapper.getAwarenessAttributes(), empty());
  81. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone(), aMapWithSize(1));
  82. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone().keySet().iterator().next(), empty());
  83. assertThat(
  84. nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone().get(List.of()),
  85. containsInAnyOrder(discoveryNodes.getNodes().values().toArray())
  86. );
  87. assertThat(nodeAvailabilityZoneMapper.getNumAvailabilityZones().getAsInt(), is(1));
  88. assertThat(nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone(), aMapWithSize(1));
  89. assertThat(nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone().keySet().iterator().next(), empty());
  90. assertThat(
  91. nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone().get(List.of()),
  92. containsInAnyOrder(discoveryNodes.getNodes().values().toArray())
  93. );
  94. assertThat(nodeAvailabilityZoneMapper.getNumMlAvailabilityZones().getAsInt(), is(1));
  95. }
  96. public void testAvailabilityZonesNotConfiguredDedicatedNodes() {
  97. Settings settings = Settings.EMPTY;
  98. ClusterSettings clusterSettings = new ClusterSettings(
  99. settings,
  100. Set.of(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING)
  101. );
  102. DiscoveryNode mlNode = new DiscoveryNode(
  103. "node-1",
  104. new TransportAddress(InetAddress.getLoopbackAddress(), 9300),
  105. Map.of(),
  106. Set.of(ML_ROLE),
  107. Version.CURRENT
  108. );
  109. DiscoveryNodes discoveryNodes = DiscoveryNodes.builder()
  110. .add(mlNode)
  111. .add(
  112. new DiscoveryNode(
  113. "node-2",
  114. new TransportAddress(InetAddress.getLoopbackAddress(), 9301),
  115. Map.of(),
  116. Set.of(MASTER_ROLE),
  117. Version.CURRENT
  118. )
  119. )
  120. .add(
  121. new DiscoveryNode(
  122. "node-3",
  123. new TransportAddress(InetAddress.getLoopbackAddress(), 9202),
  124. Map.of(),
  125. Set.of(DATA_ROLE),
  126. Version.CURRENT
  127. )
  128. )
  129. .build();
  130. NodeAvailabilityZoneMapper nodeAvailabilityZoneMapper = new NodeAvailabilityZoneMapper(settings, clusterSettings, discoveryNodes);
  131. assertThat(nodeAvailabilityZoneMapper.getAwarenessAttributes(), empty());
  132. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone(), aMapWithSize(1));
  133. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone().keySet().iterator().next(), empty());
  134. assertThat(
  135. nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone().get(List.of()),
  136. containsInAnyOrder(discoveryNodes.getNodes().values().toArray())
  137. );
  138. assertThat(nodeAvailabilityZoneMapper.getNumAvailabilityZones().getAsInt(), is(1));
  139. assertThat(nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone(), aMapWithSize(1));
  140. assertThat(nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone().keySet().iterator().next(), empty());
  141. assertThat(nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone().get(List.of()), contains(mlNode));
  142. assertThat(nodeAvailabilityZoneMapper.getNumMlAvailabilityZones().getAsInt(), is(1));
  143. }
  144. public void testAvailabilityZonesConfiguredMultiRoleNodes() {
  145. Settings settings = Settings.builder()
  146. .putList(
  147. AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(),
  148. List.of("region", "logical_availability_zone")
  149. )
  150. .build();
  151. ClusterSettings clusterSettings = new ClusterSettings(
  152. settings,
  153. Set.of(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING)
  154. );
  155. DiscoveryNodes.Builder discoveryNodesBuilder = DiscoveryNodes.builder();
  156. int numNodes = randomIntBetween(2, 50);
  157. int numZones = randomIntBetween(1, Math.min(numNodes, 3));
  158. for (int nodeNum = 1; nodeNum <= numNodes; ++nodeNum) {
  159. discoveryNodesBuilder.add(
  160. new DiscoveryNode(
  161. "node-" + nodeNum,
  162. new TransportAddress(InetAddress.getLoopbackAddress(), 9299 + nodeNum),
  163. Map.of("region", "unknown-region", "logical_availability_zone", "zone-" + (nodeNum % numZones)),
  164. Set.of(MASTER_ROLE, DATA_ROLE, ML_ROLE),
  165. Version.CURRENT
  166. )
  167. );
  168. }
  169. DiscoveryNodes discoveryNodes = discoveryNodesBuilder.build();
  170. NodeAvailabilityZoneMapper nodeAvailabilityZoneMapper = new NodeAvailabilityZoneMapper(settings, clusterSettings, discoveryNodes);
  171. assertThat(nodeAvailabilityZoneMapper.getAwarenessAttributes(), equalTo(List.of("region", "logical_availability_zone")));
  172. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone(), aMapWithSize(numZones));
  173. int totalNodesMapped = 0;
  174. for (Map.Entry<List<String>, Collection<DiscoveryNode>> entry : nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone()
  175. .entrySet()) {
  176. List<String> key = entry.getKey();
  177. assertThat(key, hasSize(2));
  178. assertThat(key.get(0), equalTo("unknown-region"));
  179. String zoneAttributeValue = key.get(1);
  180. for (DiscoveryNode node : entry.getValue()) {
  181. assertThat(node.getAttributes().get("logical_availability_zone"), equalTo(zoneAttributeValue));
  182. ++totalNodesMapped;
  183. }
  184. }
  185. assertThat(totalNodesMapped, is(numNodes));
  186. assertThat(nodeAvailabilityZoneMapper.getNumAvailabilityZones().getAsInt(), is(numZones));
  187. totalNodesMapped = 0;
  188. for (Map.Entry<List<String>, Collection<DiscoveryNode>> entry : nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone()
  189. .entrySet()) {
  190. List<String> key = entry.getKey();
  191. assertThat(key, hasSize(2));
  192. assertThat(key.get(0), equalTo("unknown-region"));
  193. String zoneAttributeValue = key.get(1);
  194. for (DiscoveryNode node : entry.getValue()) {
  195. assertThat(node.getAttributes().get("logical_availability_zone"), equalTo(zoneAttributeValue));
  196. ++totalNodesMapped;
  197. }
  198. }
  199. assertThat(totalNodesMapped, is(numNodes));
  200. assertThat(nodeAvailabilityZoneMapper.getNumMlAvailabilityZones().getAsInt(), is(numZones));
  201. }
  202. public void testAvailabilityZonesConfiguredDedicatedNodes() {
  203. Settings settings = Settings.builder()
  204. .putList(
  205. AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING.getKey(),
  206. List.of("region", "logical_availability_zone")
  207. )
  208. .build();
  209. ClusterSettings clusterSettings = new ClusterSettings(
  210. settings,
  211. Set.of(AwarenessAllocationDecider.CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING)
  212. );
  213. List<DiscoveryNode> mlNodes = new ArrayList<>();
  214. Set<Integer> mlZones = new HashSet<>();
  215. DiscoveryNodes.Builder discoveryNodesBuilder = DiscoveryNodes.builder();
  216. int numNodes = randomIntBetween(10, 50);
  217. int numZones = randomIntBetween(2, 3);
  218. int numMlZones = randomIntBetween(1, numZones);
  219. for (int nodeNum = 1; nodeNum <= numNodes; ++nodeNum) {
  220. int zone = nodeNum % numZones;
  221. DiscoveryNodeRole role = (zone < numMlZones) ? randomFrom(MASTER_ROLE, DATA_ROLE, ML_ROLE) : randomFrom(MASTER_ROLE, DATA_ROLE);
  222. DiscoveryNode node = new DiscoveryNode(
  223. "node-" + nodeNum,
  224. new TransportAddress(InetAddress.getLoopbackAddress(), 9199 + nodeNum),
  225. Map.of("region", "unknown-region", "logical_availability_zone", "zone-" + zone),
  226. Set.of(role),
  227. Version.CURRENT
  228. );
  229. if (role == ML_ROLE) {
  230. mlNodes.add(node);
  231. mlZones.add(zone);
  232. }
  233. discoveryNodesBuilder.add(node);
  234. }
  235. DiscoveryNodes discoveryNodes = discoveryNodesBuilder.build();
  236. NodeAvailabilityZoneMapper nodeAvailabilityZoneMapper = new NodeAvailabilityZoneMapper(settings, clusterSettings, discoveryNodes);
  237. assertThat(nodeAvailabilityZoneMapper.getAwarenessAttributes(), equalTo(List.of("region", "logical_availability_zone")));
  238. assertThat(nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone(), aMapWithSize(numZones));
  239. int totalNodesMapped = 0;
  240. for (Map.Entry<List<String>, Collection<DiscoveryNode>> entry : nodeAvailabilityZoneMapper.getAllNodesByAvailabilityZone()
  241. .entrySet()) {
  242. List<String> key = entry.getKey();
  243. assertThat(key, hasSize(2));
  244. assertThat(key.get(0), equalTo("unknown-region"));
  245. String zoneAttributeValue = key.get(1);
  246. for (DiscoveryNode node : entry.getValue()) {
  247. assertThat(node.getAttributes().get("logical_availability_zone"), equalTo(zoneAttributeValue));
  248. ++totalNodesMapped;
  249. }
  250. }
  251. assertThat(totalNodesMapped, is(numNodes));
  252. assertThat(nodeAvailabilityZoneMapper.getNumAvailabilityZones().getAsInt(), is(numZones));
  253. int totalMlNodesMapped = 0;
  254. for (Map.Entry<List<String>, Collection<DiscoveryNode>> entry : nodeAvailabilityZoneMapper.getMlNodesByAvailabilityZone()
  255. .entrySet()) {
  256. List<String> key = entry.getKey();
  257. assertThat(key, hasSize(2));
  258. assertThat(key.get(0), equalTo("unknown-region"));
  259. String zoneAttributeValue = key.get(1);
  260. for (DiscoveryNode node : entry.getValue()) {
  261. assertThat(node.getAttributes().get("logical_availability_zone"), equalTo(zoneAttributeValue));
  262. ++totalMlNodesMapped;
  263. }
  264. }
  265. assertThat(totalMlNodesMapped, is(mlNodes.size()));
  266. assertThat(nodeAvailabilityZoneMapper.getNumMlAvailabilityZones().getAsInt(), is(mlZones.size()));
  267. }
  268. }