Skip to content

Introduce system index APIs for Kibana #52385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Mar 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9e8c213
Introduce system index APIs for Kibana
jaymode Jan 28, 2020
80c8c76
update method signatures
jaymode Feb 14, 2020
8cb8a65
s/compileOnly/compile
jaymode Feb 14, 2020
39b6290
fix threadcontext serialization
jaymode Feb 18, 2020
3d80bd3
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 18, 2020
758409c
add simple test for client that limits requests/indices
jaymode Feb 18, 2020
4577616
set version on streamgit add .git add .git add .
jaymode Feb 18, 2020
46325b2
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 19, 2020
b0194a8
add tests for APIs
jaymode Feb 19, 2020
86a27ce
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 20, 2020
16e5e87
rest controller test for system index restriction
jaymode Feb 20, 2020
d9fa9ae
threadcontext tests
jaymode Feb 20, 2020
15aad51
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 20, 2020
2dabec8
no randomBoolean in static value
jaymode Feb 20, 2020
43e735e
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 25, 2020
3bf05f1
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 26, 2020
2a74996
add APIs listed in Kibana issue
jaymode Feb 26, 2020
2a8b637
add reporting
jaymode Feb 26, 2020
863fe79
address description
jaymode Feb 27, 2020
b1c53f7
ESRestTestCase
jaymode Feb 27, 2020
eaac89d
cleanup stream version setting
jaymode Feb 27, 2020
43d4134
Fix version on CompressibleBytesOutputStream
jaymode Feb 27, 2020
954bcad
Merge branch 'master' into kibana_system_index_plugin
jaymode Feb 27, 2020
5778129
remove limiting of indices
jaymode Feb 27, 2020
52b609d
add tests for rest of apis
jaymode Feb 27, 2020
681924e
Merge branch 'master' into kibana_system_index_plugin
jaymode Mar 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions modules/kibana/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.
*/

esplugin {
description 'Plugin exposing APIs for Kibana system indices'
classname 'org.elasticsearch.kibana.KibanaPlugin'
}

dependencies {
compile project(path: ':modules:reindex', configuration: 'runtime')
}

testClusters.integTest {
module file(project(':modules:reindex').tasks.bundlePlugin.archiveFile)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
* 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.kibana;

import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.index.reindex.RestDeleteByQueryAction;
import org.elasticsearch.indices.SystemIndexDescriptor;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.SystemIndexPlugin;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.admin.indices.RestCreateIndexAction;
import org.elasticsearch.rest.action.admin.indices.RestGetAliasesAction;
import org.elasticsearch.rest.action.admin.indices.RestGetIndicesAction;
import org.elasticsearch.rest.action.admin.indices.RestIndexPutAliasAction;
import org.elasticsearch.rest.action.admin.indices.RestRefreshAction;
import org.elasticsearch.rest.action.admin.indices.RestUpdateSettingsAction;
import org.elasticsearch.rest.action.document.RestBulkAction;
import org.elasticsearch.rest.action.document.RestDeleteAction;
import org.elasticsearch.rest.action.document.RestGetAction;
import org.elasticsearch.rest.action.document.RestIndexAction;
import org.elasticsearch.rest.action.document.RestIndexAction.AutoIdHandler;
import org.elasticsearch.rest.action.document.RestIndexAction.CreateHandler;
import org.elasticsearch.rest.action.document.RestMultiGetAction;
import org.elasticsearch.rest.action.document.RestUpdateAction;
import org.elasticsearch.rest.action.search.RestClearScrollAction;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.rest.action.search.RestSearchScrollAction;

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class KibanaPlugin extends Plugin implements SystemIndexPlugin {

public static final Setting<List<String>> KIBANA_INDEX_NAMES_SETTING = Setting.listSetting("kibana.system_indices",
Copy link
Member Author

@jaymode jaymode Feb 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylersmalley I was looking at elastic/kibana#49764 and I wanted to make sure I understood the request there for the paths where you have _kibana/{kibana.name}/ and kibana.name would be understood by elasticsearch based on settings.

Right now in this plugin, the setting I have would look like this in the elasticsearch.yml file:

kibana.system_indices: [ ".kibana", ".kibana_task_manager", ".reporting" ]

I think the Kibana issue is actually looking for something more like:

kibana:
  instances:
    my_kibana:
       kibana_index: ".my-kibana"
       task_manager_index: ".my-tm"
       reporting_index: ".my-reports"

Is this correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latter is correct. Ideally, I would like to define a list of names which we could derive each index off of, but that won't work today as users can configure them individually.

In that example, would the endpoint be _kibana/my_kibana/*?

It would probably also make sense to include a default so Kibana instance configuration is only necessary if they intend on having multiple instances.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that would be the endpoint path. For the default, I think we will still want an instance name so maybe just ‘kibana’ for that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Though, could we use default for the name of the default instance? I feel this should be clear as to what the instance is and avoid _kibana/kibana/*

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the risk for not whitelisting kibana instances and indices? From a user's perspective it's error prone to have to adjust both the kibana and elasticsearch config files and keep them in sync. The status quo is that Kibana creates any instances (it's currently just an index prefix) and indices it wants to.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every system index plugin needs to declare the system indices it is used for as a way to identify indices that are system indices. If you are ok with just creating all of your indices under a single prefix, then I think that would be fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question was also brought up as to if we would consider this a breaking change if it was introduced before 8.0. Currently, to migrate to the system indices the user would be required to update ES and Kibana configuration.

The prefixing is interesting idea worth exploring, but would require coming up with a plan to migrate to these index names, correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point on it being breaking. One thing we can do is allow the APIs under /_kibana to be unrestricted for the indices that could be used in 7.x.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the time being, I have gone ahead and removed the limiting of indices accessible by the APIs until we figure out what we should do here regarding these indices and their names.

List.of(".kibana*", ".reporting"), Function.identity(), Property.NodeScope);

@Override
public Collection<SystemIndexDescriptor> getSystemIndexDescriptors(Settings settings) {
return KIBANA_INDEX_NAMES_SETTING.get(settings).stream()
.map(pattern -> new SystemIndexDescriptor(pattern, "System index used by kibana"))
.collect(Collectors.toUnmodifiableList());
}

@Override
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter,
IndexNameExpressionResolver indexNameExpressionResolver,
Supplier<DiscoveryNodes> nodesInCluster) {
// TODO need to figure out what subset of system indices Kibana should have access to via these APIs
final List<String> allowedIndexPatterns = List.of();
return List.of(
// Based on https://github.com/elastic/kibana/issues/49764
// apis needed to perform migrations... ideally these will go away
new KibanaWrappedRestHandler(new RestCreateIndexAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestGetAliasesAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestIndexPutAliasAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestRefreshAction(), allowedIndexPatterns),

// apis needed to access saved objects
new KibanaWrappedRestHandler(new RestGetAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestMultiGetAction(settings), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestSearchAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestBulkAction(settings), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestDeleteAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestDeleteByQueryAction(), allowedIndexPatterns),

// api used for testing
new KibanaWrappedRestHandler(new RestUpdateSettingsAction(), allowedIndexPatterns),

// apis used specifically by reporting
new KibanaWrappedRestHandler(new RestGetIndicesAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestIndexAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new CreateHandler(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new AutoIdHandler(nodesInCluster), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestUpdateAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestSearchScrollAction(), allowedIndexPatterns),
new KibanaWrappedRestHandler(new RestClearScrollAction(), allowedIndexPatterns)
);

}

@Override
public List<Setting<?>> getSettings() {
return List.of(KIBANA_INDEX_NAMES_SETTING);
}

static class KibanaWrappedRestHandler extends BaseRestHandler.Wrapper {

private final List<String> allowedIndexPatterns;

KibanaWrappedRestHandler(BaseRestHandler delegate, List<String> allowedIndexPatterns) {
super(delegate);
this.allowedIndexPatterns = allowedIndexPatterns;
}

@Override
public String getName() {
return "kibana_" + super.getName();
}

@Override
public List<Route> routes() {
return super.routes().stream().map(route -> new Route(route.getMethod(), "/_kibana" + route.getPath()))
.collect(Collectors.toUnmodifiableList());
}

@Override
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
client.threadPool().getThreadContext().allowSystemIndexAccess(allowedIndexPatterns);
return super.prepareRequest(request, client);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

/*
* 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.kibana;

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.indices.SystemIndexDescriptor;
import org.elasticsearch.test.ESTestCase;

import java.util.List;
import java.util.stream.Collectors;

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;

public class KibanaPluginTests extends ESTestCase {

public void testKibanaIndexNames() {
assertThat(new KibanaPlugin().getSettings(), contains(KibanaPlugin.KIBANA_INDEX_NAMES_SETTING));
assertThat(new KibanaPlugin().getSystemIndexDescriptors(Settings.EMPTY).stream()
.map(SystemIndexDescriptor::getIndexPattern).collect(Collectors.toUnmodifiableList()),
contains(".kibana*", ".reporting"));
final List<String> names = List.of("." + randomAlphaOfLength(4), "." + randomAlphaOfLength(6));
final List<String> namesFromDescriptors = new KibanaPlugin().getSystemIndexDescriptors(
Settings.builder().putList(KibanaPlugin.KIBANA_INDEX_NAMES_SETTING.getKey(), names).build()
).stream().map(SystemIndexDescriptor::getIndexPattern).collect(Collectors.toUnmodifiableList());
assertThat(namesFromDescriptors, is(names));
}
}
Loading