Skip to content

Commit 435bd33

Browse files
committed
Add user-defined cluster metadata (elastic#33325)
Adds a place for users to store cluster-wide data they wish to associate with the cluster via the Cluster Settings API. This is strictly for user-defined data, Elasticsearch makes no other other use of these settings.
1 parent 1498b7c commit 435bd33

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

docs/reference/modules/cluster/misc.asciidoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@ user with access to the <<cluster-update-settings,cluster-update-settings>>
2222
API can make the cluster read-write again.
2323

2424

25+
[[user-defined-data]]
26+
==== User Defined Cluster Metadata
27+
28+
User-defined metadata can be stored and retrieved using the Cluster Settings API.
29+
This can be used to store arbitrary, infrequently-changing data about the cluster
30+
without the need to create an index to store it. This data may be stored using
31+
any key prefixed with `cluster.metadata.`. For example, to store the email
32+
address of the administrator of a cluster under the key `cluster.metadata.administrator`,
33+
issue this request:
34+
35+
[source,js]
36+
-------------------------------
37+
PUT /_cluster/settings
38+
{
39+
"persistent": {
40+
"cluster.metadata.administrator": "sysadmin@example.com"
41+
}
42+
}
43+
-------------------------------
44+
// CONSOLE
45+
2546
[[cluster-max-tombstones]]
2647
==== Index Tombstones
2748

server/src/main/java/org/elasticsearch/cluster/service/ClusterService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public class ClusterService extends AbstractLifecycleComponent {
5252
Setting.positiveTimeSetting("cluster.service.slow_task_logging_threshold", TimeValue.timeValueSeconds(30),
5353
Property.Dynamic, Property.NodeScope);
5454

55+
public static final org.elasticsearch.common.settings.Setting.AffixSetting<String> USER_DEFINED_META_DATA =
56+
Setting.prefixKeySetting("cluster.metadata.", (key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope));
57+
5558
private final ClusterName clusterName;
5659

5760
private final OperationRouting operationRouting;
@@ -68,6 +71,8 @@ public ClusterService(Settings settings, ClusterSettings clusterSettings, Thread
6871
this.clusterName = ClusterName.CLUSTER_NAME_SETTING.get(settings);
6972
this.clusterSettings.addSettingsUpdateConsumer(CLUSTER_SERVICE_SLOW_TASK_LOGGING_THRESHOLD_SETTING,
7073
this::setSlowTaskLoggingThreshold);
74+
// Add a no-op update consumer so changes are logged
75+
this.clusterSettings.addAffixUpdateConsumer(USER_DEFINED_META_DATA, (first, second) -> {}, (first, second) -> {});
7176
this.initialClusterStateCustoms = initialClusterStateCustoms;
7277
this.clusterApplierService = new ClusterApplierService(settings, clusterSettings, threadPool, this::newClusterStateBuilder);
7378
}

server/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ public void apply(Settings value, Settings current, Settings previous) {
269269
HierarchyCircuitBreakerService.ACCOUNTING_CIRCUIT_BREAKER_OVERHEAD_SETTING,
270270
IndexModule.NODE_STORE_ALLOW_MMAPFS,
271271
ClusterService.CLUSTER_SERVICE_SLOW_TASK_LOGGING_THRESHOLD_SETTING,
272+
ClusterService.USER_DEFINED_META_DATA,
272273
SearchService.DEFAULT_SEARCH_TIMEOUT_SETTING,
273274
SearchService.DEFAULT_ALLOW_PARTIAL_SEARCH_RESULTS,
274275
ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING,

server/src/test/java/org/elasticsearch/cluster/settings/ClusterSettingsIT.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.logging.log4j.Level;
2323
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequestBuilder;
2424
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
25+
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
2526
import org.elasticsearch.cluster.metadata.MetaData;
2627
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
2728
import org.elasticsearch.common.logging.ESLoggerFactory;
@@ -380,4 +381,34 @@ public void testLoggerLevelUpdate() {
380381
}
381382
}
382383

384+
public void testUserMetadata() {
385+
String key = "cluster.metadata." + randomAlphaOfLengthBetween(5, 20);
386+
String value = randomRealisticUnicodeOfCodepointLengthBetween(5, 50);
387+
String updatedValue = randomRealisticUnicodeOfCodepointLengthBetween(5, 50);
388+
logger.info("Attempting to store [{}]: [{}], then update to [{}]", key, value, updatedValue);
389+
390+
final Settings settings = Settings.builder().put(key, value).build();
391+
final Settings updatedSettings = Settings.builder().put(key, updatedValue).build();
392+
if (randomBoolean()) {
393+
logger.info("Using persistent settings");
394+
395+
client().admin().cluster().prepareUpdateSettings().setPersistentSettings(settings).execute().actionGet();
396+
ClusterStateResponse state = client().admin().cluster().prepareState().execute().actionGet();
397+
assertEquals(value, state.getState().getMetaData().persistentSettings().get(key));
398+
399+
client().admin().cluster().prepareUpdateSettings().setPersistentSettings(updatedSettings).execute().actionGet();
400+
ClusterStateResponse updatedState = client().admin().cluster().prepareState().execute().actionGet();
401+
assertEquals(updatedValue, updatedState.getState().getMetaData().persistentSettings().get(key));
402+
} else {
403+
logger.info("Using transient settings");
404+
client().admin().cluster().prepareUpdateSettings().setTransientSettings(settings).execute().actionGet();
405+
ClusterStateResponse state = client().admin().cluster().prepareState().execute().actionGet();
406+
assertEquals(value, state.getState().getMetaData().transientSettings().get(key));
407+
408+
client().admin().cluster().prepareUpdateSettings().setTransientSettings(updatedSettings).execute().actionGet();
409+
ClusterStateResponse updatedState = client().admin().cluster().prepareState().execute().actionGet();
410+
assertEquals(updatedValue, updatedState.getState().getMetaData().transientSettings().get(key));
411+
}
412+
}
413+
383414
}

0 commit comments

Comments
 (0)