Skip to content

Commit

Permalink
Internal: refactor settings filtering
Browse files Browse the repository at this point in the history
Refactor how settings filters are handled. Instead of specifying settings filters as filtering class, settings filters are now specified as list of settings that needs to be filtered out. Regex syntax is supported. This is breaking change and will require small change in plugins that are using settingsFilters. This change is needed in order to simplify cluster state diff implementation.

Contributes to #6295
  • Loading branch information
imotov committed Feb 24, 2015
1 parent ff8fd67 commit 432f578
Show file tree
Hide file tree
Showing 11 changed files with 337 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
*/
public class NodesInfoResponse extends NodesOperationResponse<NodeInfo> implements ToXContent {

private SettingsFilter settingsFilter;

public NodesInfoResponse() {
}

Expand All @@ -64,11 +62,6 @@ public void writeTo(StreamOutput out) throws IOException {
}
}

public NodesInfoResponse settingsFilter(SettingsFilter settingsFilter) {
this.settingsFilter = settingsFilter;
return this;
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field("cluster_name", getClusterName().value(), XContentBuilder.FieldCaseConversion.NONE);
Expand Down Expand Up @@ -102,7 +95,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws

if (nodeInfo.getSettings() != null) {
builder.startObject("settings");
Settings settings = settingsFilter != null ? settingsFilter.filterSettings(nodeInfo.getSettings()) : nodeInfo.getSettings();
Settings settings = nodeInfo.getSettings();
settings.toXContent(builder, params);
builder.endObject();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ protected void masterOperation(GetSettingsRequest request, ClusterState state, A
continue;
}

Settings settings = settingsFilter.filterSettings(indexMetaData.settings());
Settings settings = SettingsFilter.filterSettings(settingsFilter.getPatterns(), indexMetaData.settings());
if (!CollectionUtils.isEmpty(request.names())) {
ImmutableSettings.Builder settingsBuilder = ImmutableSettings.builder();
for (Map.Entry<String, String> entry : settings.getAsMap().entrySet()) {
Expand Down
16 changes: 1 addition & 15 deletions src/main/java/org/elasticsearch/cluster/ClusterState.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.routing.*;
import org.elasticsearch.cluster.routing.allocation.AllocationExplanation;

import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
Expand All @@ -44,7 +44,6 @@
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
Expand Down Expand Up @@ -134,8 +133,6 @@ public static <T extends Custom> Custom.Factory<T> lookupFactorySafe(String type
// built on demand
private volatile RoutingNodes routingNodes;

private SettingsFilter settingsFilter;

private volatile ClusterStateStatus status;

public ClusterState(long version, ClusterState state) {
Expand Down Expand Up @@ -234,11 +231,6 @@ public RoutingNodes readOnlyRoutingNodes() {
return routingNodes;
}

public ClusterState settingsFilter(SettingsFilter settingsFilter) {
this.settingsFilter = settingsFilter;
return this;
}

public String prettyPrint() {
StringBuilder sb = new StringBuilder();
sb.append("version: ").append(version).append("\n");
Expand Down Expand Up @@ -385,9 +377,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws

builder.startObject("settings");
Settings settings = templateMetaData.settings();
if (settingsFilter != null) {
settings = settingsFilter.filterSettings(settings);
}
settings.toXContent(builder, params);
builder.endObject();

Expand Down Expand Up @@ -418,9 +407,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws

builder.startObject("settings");
Settings settings = indexMetaData.settings();
if (settingsFilter != null) {
settings = settingsFilter.filterSettings(settings);
}
settings.toXContent(builder, params);
builder.endObject();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -648,12 +648,13 @@ public static Builder settingsBuilder() {

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
Settings settings = SettingsFilter.filterSettings(params, this);
if (!params.paramAsBoolean("flat_settings", false)) {
for (Map.Entry<String, Object> entry : getAsStructuredMap().entrySet()) {
for (Map.Entry<String, Object> entry : settings.getAsStructuredMap().entrySet()) {
builder.field(entry.getKey(), entry.getValue());
}
} else {
for (Map.Entry<String, String> entry : getAsMap().entrySet()) {
for (Map.Entry<String, String> entry : settings.getAsMap().entrySet()) {
builder.field(entry.getKey(), entry.getValue(), XContentBuilder.FieldCaseConversion.NONE);
}
}
Expand Down
82 changes: 68 additions & 14 deletions src/main/java/org/elasticsearch/common/settings/SettingsFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,95 @@
*/
package org.elasticsearch.common.settings;

import org.elasticsearch.common.Strings;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.xcontent.ToXContent.Params;
import org.elasticsearch.rest.RestRequest;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CopyOnWriteArrayList;

import static com.google.common.collect.Lists.newArrayList;

/**
*
*/
public class SettingsFilter extends AbstractComponent {
/**
* Can be used to specify settings filter that will be used to filter out matching settings in toXContent method
*/
public static String SETTINGS_FILTER_PARAM = "settings_filter";

public static interface Filter {

void filter(ImmutableSettings.Builder settings);
}

private final CopyOnWriteArrayList<Filter> filters = new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList<String> patterns = new CopyOnWriteArrayList<>();

@Inject
public SettingsFilter(Settings settings) {
super(settings);
}

public void addFilter(Filter filter) {
filters.add(filter);
/**
* Adds a new simple pattern to the list of filters
*
* @param pattern
*/
public void addFilter(String pattern) {
patterns.add(pattern);
}

public void removeFilter(Filter filter) {
filters.remove(filter);
/**
* Removes a simple pattern from the list of filters
*
* @param pattern
*/
public void removeFilter(String pattern) {
patterns.remove(pattern);
}

public Settings filterSettings(Settings settings) {
public String getPatterns() {
return Strings.collectionToDelimitedString(patterns, ",");
}

public void addFilterSettingParams(RestRequest request) {
if (patterns.isEmpty() == false) {
request.params().put(SETTINGS_FILTER_PARAM, getPatterns());
}
}

public static Settings filterSettings(Params params, Settings settings) {
String patterns = params.param(SETTINGS_FILTER_PARAM);
Settings filteredSettings = settings;
if (patterns != null && patterns.isEmpty() == false) {
filteredSettings = SettingsFilter.filterSettings(patterns, filteredSettings);
}
return filteredSettings;
}

public static Settings filterSettings(String patterns, Settings settings) {
String[] patternArray = Strings.delimitedListToStringArray(patterns, ",");
ImmutableSettings.Builder builder = ImmutableSettings.settingsBuilder().put(settings);
for (Filter filter : filters) {
filter.filter(builder);
List<String> simpleMatchPatternList = newArrayList();
for (String pattern : patternArray) {
if (Regex.isSimpleMatchPattern(pattern)) {
simpleMatchPatternList.add(pattern);
} else {
builder.remove(pattern);
}
}
if (!simpleMatchPatternList.isEmpty()) {
String[] simpleMatchPatterns = simpleMatchPatternList.toArray(new String[simpleMatchPatternList.size()]);
Iterator<Entry<String, String>> iterator = builder.internalMap().entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> current = iterator.next();
if (Regex.simpleMatch(simpleMatchPatterns, current.getKey())) {
iterator.remove();
}
}
}
return builder.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ public void handleRequest(final RestRequest request, final RestChannel channel,
nodesInfoRequest.plugins(metrics.contains("plugins"));
}

settingsFilter.addFilterSettingParams(request);

client.admin().cluster().nodesInfo(nodesInfoRequest, new RestBuilderListener<NodesInfoResponse>(channel) {

@Override
public RestResponse buildResponse(NodesInfoResponse response, XContentBuilder builder) throws Exception {
response.settingsFilter(settingsFilter);
builder.startObject();
response.toXContent(builder, request);
builder.endObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ protected void addCustomFields(XContentBuilder builder, ClusterRerouteResponse r
if (request.param("metric") == null) {
request.params().put("metric", DEFAULT_METRICS);
}
response.getState().settingsFilter(settingsFilter).toXContent(builder, request);
settingsFilter.addFilterSettingParams(request);
response.getState().toXContent(builder, request);
builder.endObject();
if (clusterRerouteRequest.explain()) {
assert response.getExplanations() != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ public void handleRequest(final RestRequest request, final RestChannel channel,
clusterStateRequest.metaData(metrics.contains(ClusterState.Metric.METADATA));
clusterStateRequest.blocks(metrics.contains(ClusterState.Metric.BLOCKS));
}
settingsFilter.addFilterSettingParams(request);

client.admin().cluster().state(clusterStateRequest, new RestBuilderListener<ClusterStateResponse>(channel) {
@Override
public RestResponse buildResponse(ClusterStateResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
builder.field(Fields.CLUSTER_NAME, response.getClusterName().value());
response.getState().settingsFilter(settingsFilter).toXContent(builder, request);
response.getState().toXContent(builder, request);
builder.endObject();
return new BytesRestResponse(RestStatus.OK, builder);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.cluster.settings;

import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.plugins.AbstractPlugin;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.junit.Test;

import java.util.Collection;

import static com.google.common.collect.Lists.newArrayList;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.nullValue;

@ClusterScope(scope = SUITE, numDataNodes = 1)
public class SettingsFilteringTests extends ElasticsearchIntegrationTest {

@Override
protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal))
.put("plugin.types", SettingsFilteringPlugin.class.getName())
.build();
}

public static class SettingsFilteringPlugin extends AbstractPlugin {
/**
* The name of the plugin.
*/
@Override
public String name() {
return "settings-filtering";
}

/**
* The description of the plugin.
*/
@Override
public String description() {
return "Settings Filtering Plugin";
}

@Override
public Collection<Class<? extends Module>> indexModules() {
Collection<Class<? extends Module>> modules = newArrayList();
modules.add(SettingsFilteringModule.class);
return modules;
}
}

public static class SettingsFilteringModule extends AbstractModule {

@Override
protected void configure() {
bind(SettingsFilteringService.class).asEagerSingleton();
}
}

public static class SettingsFilteringService {
@Inject
public SettingsFilteringService(SettingsFilter settingsFilter) {
settingsFilter.addFilter("index.filter_test.foo");
settingsFilter.addFilter("index.filter_test.bar*");
}
}


@Test
public void testSettingsFiltering() {

assertAcked(client().admin().indices().prepareCreate("test-idx").setSettings(ImmutableSettings.builder()
.put("filter_test.foo", "test")
.put("filter_test.bar1", "test")
.put("filter_test.bar2", "test")
.put("filter_test.notbar", "test")
.put("filter_test.notfoo", "test")
.build()).get());
GetSettingsResponse response = client().admin().indices().prepareGetSettings("test-idx").get();
Settings settings = response.getIndexToSettings().get("test-idx");

assertThat(settings.get("index.filter_test.foo"), nullValue());
assertThat(settings.get("index.filter_test.bar1"), nullValue());
assertThat(settings.get("index.filter_test.bar2"), nullValue());
assertThat(settings.get("index.filter_test.notbar"), equalTo("test"));
assertThat(settings.get("index.filter_test.notfoo"), equalTo("test"));
}

}
Loading

0 comments on commit 432f578

Please sign in to comment.