Add user-defined cluster metadata (#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.
This commit is contained in:
Gordon Brown 2018-09-04 16:14:18 -06:00 committed by GitHub
parent 48790b0aad
commit cfd3fa72ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 0 deletions

View File

@ -22,6 +22,27 @@ user with access to the <<cluster-update-settings,cluster-update-settings>>
API can make the cluster read-write again.
[[user-defined-data]]
==== User Defined Cluster Metadata
User-defined metadata can be stored and retrieved using the Cluster Settings API.
This can be used to store arbitrary, infrequently-changing data about the cluster
without the need to create an index to store it. This data may be stored using
any key prefixed with `cluster.metadata.`. For example, to store the email
address of the administrator of a cluster under the key `cluster.metadata.administrator`,
issue this request:
[source,js]
-------------------------------
PUT /_cluster/settings
{
"persistent": {
"cluster.metadata.administrator": "sysadmin@example.com"
}
}
-------------------------------
// CONSOLE
[[cluster-max-tombstones]]
==== Index Tombstones

View File

@ -53,6 +53,9 @@ public class ClusterService extends AbstractLifecycleComponent {
Setting.positiveTimeSetting("cluster.service.slow_task_logging_threshold", TimeValue.timeValueSeconds(30),
Property.Dynamic, Property.NodeScope);
public static final org.elasticsearch.common.settings.Setting.AffixSetting<String> USER_DEFINED_META_DATA =
Setting.prefixKeySetting("cluster.metadata.", (key) -> Setting.simpleString(key, Property.Dynamic, Property.NodeScope));
private final ClusterName clusterName;
private final OperationRouting operationRouting;
@ -67,6 +70,8 @@ public class ClusterService extends AbstractLifecycleComponent {
this.clusterName = ClusterName.CLUSTER_NAME_SETTING.get(settings);
this.clusterSettings.addSettingsUpdateConsumer(CLUSTER_SERVICE_SLOW_TASK_LOGGING_THRESHOLD_SETTING,
this::setSlowTaskLoggingThreshold);
// Add a no-op update consumer so changes are logged
this.clusterSettings.addAffixUpdateConsumer(USER_DEFINED_META_DATA, (first, second) -> {}, (first, second) -> {});
this.clusterApplierService = new ClusterApplierService(settings, clusterSettings, threadPool);
}

View File

@ -267,6 +267,7 @@ public final class ClusterSettings extends AbstractScopedSettings {
HierarchyCircuitBreakerService.ACCOUNTING_CIRCUIT_BREAKER_OVERHEAD_SETTING,
IndexModule.NODE_STORE_ALLOW_MMAPFS,
ClusterService.CLUSTER_SERVICE_SLOW_TASK_LOGGING_THRESHOLD_SETTING,
ClusterService.USER_DEFINED_META_DATA,
SearchService.DEFAULT_SEARCH_TIMEOUT_SETTING,
SearchService.DEFAULT_ALLOW_PARTIAL_SEARCH_RESULTS,
ElectMasterService.DISCOVERY_ZEN_MINIMUM_MASTER_NODES_SETTING,

View File

@ -22,6 +22,7 @@ package org.elasticsearch.cluster.settings;
import org.apache.logging.log4j.Level;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequestBuilder;
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider;
import org.elasticsearch.common.logging.ESLoggerFactory;
@ -380,4 +381,34 @@ public class ClusterSettingsIT extends ESIntegTestCase {
}
}
public void testUserMetadata() {
String key = "cluster.metadata." + randomAlphaOfLengthBetween(5, 20);
String value = randomRealisticUnicodeOfCodepointLengthBetween(5, 50);
String updatedValue = randomRealisticUnicodeOfCodepointLengthBetween(5, 50);
logger.info("Attempting to store [{}]: [{}], then update to [{}]", key, value, updatedValue);
final Settings settings = Settings.builder().put(key, value).build();
final Settings updatedSettings = Settings.builder().put(key, updatedValue).build();
if (randomBoolean()) {
logger.info("Using persistent settings");
client().admin().cluster().prepareUpdateSettings().setPersistentSettings(settings).execute().actionGet();
ClusterStateResponse state = client().admin().cluster().prepareState().execute().actionGet();
assertEquals(value, state.getState().getMetaData().persistentSettings().get(key));
client().admin().cluster().prepareUpdateSettings().setPersistentSettings(updatedSettings).execute().actionGet();
ClusterStateResponse updatedState = client().admin().cluster().prepareState().execute().actionGet();
assertEquals(updatedValue, updatedState.getState().getMetaData().persistentSettings().get(key));
} else {
logger.info("Using transient settings");
client().admin().cluster().prepareUpdateSettings().setTransientSettings(settings).execute().actionGet();
ClusterStateResponse state = client().admin().cluster().prepareState().execute().actionGet();
assertEquals(value, state.getState().getMetaData().transientSettings().get(key));
client().admin().cluster().prepareUpdateSettings().setTransientSettings(updatedSettings).execute().actionGet();
ClusterStateResponse updatedState = client().admin().cluster().prepareState().execute().actionGet();
assertEquals(updatedValue, updatedState.getState().getMetaData().transientSettings().get(key));
}
}
}