mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add usage collection for savedObject tagging (#83160)
* add so tagging usage collection * update telemetry mappings * fix types * remove check on esClient presence * update schema and README
This commit is contained in:
parent
7c80a6be68
commit
22e494e386
16 changed files with 1035 additions and 32 deletions
|
@ -1,3 +1,53 @@
|
|||
# SavedObjectsTagging
|
||||
|
||||
Add tagging capability to saved objects
|
||||
Add tagging capability to saved objects
|
||||
|
||||
## Integrating tagging on a new object type
|
||||
|
||||
In addition to use the UI api to plug the tagging feature in your application, there is a couple
|
||||
things that needs to be done on the server:
|
||||
|
||||
### Add read-access to the `tag` SO type to your feature's capabilities
|
||||
|
||||
In order to be able to fetch the tags assigned to an object, the user must have read permission
|
||||
for the `tag` saved object type. Which is why all features relying on SO tagging must update
|
||||
their capabilities.
|
||||
|
||||
```typescript
|
||||
features.registerKibanaFeature({
|
||||
id: 'myFeature',
|
||||
// ...
|
||||
privileges: {
|
||||
all: {
|
||||
// ...
|
||||
savedObject: {
|
||||
all: ['some-type'],
|
||||
read: ['tag'], // <-- HERE
|
||||
},
|
||||
},
|
||||
read: {
|
||||
// ...
|
||||
savedObject: {
|
||||
all: [],
|
||||
read: ['some-type', 'tag'], // <-- AND HERE
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Update the SOT telemetry collector schema to add the new type
|
||||
|
||||
The schema is located here: `x-pack/plugins/saved_objects_tagging/server/usage/schema.ts`. You
|
||||
just need to add the name of the SO type you are adding.
|
||||
|
||||
```ts
|
||||
export const tagUsageCollectorSchema: MakeSchemaFrom<TaggingUsageData> = {
|
||||
// ...
|
||||
types: {
|
||||
dashboard: perTypeSchema,
|
||||
visualization: perTypeSchema,
|
||||
// <-- add your type here
|
||||
},
|
||||
};
|
||||
```
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
"ui": true,
|
||||
"configPath": ["xpack", "saved_object_tagging"],
|
||||
"requiredPlugins": ["features", "management", "savedObjectsTaggingOss"],
|
||||
"requiredBundles": ["kibanaReact"]
|
||||
"requiredBundles": ["kibanaReact"],
|
||||
"optionalPlugins": ["usageCollection"]
|
||||
}
|
||||
|
|
|
@ -8,3 +8,8 @@ export const registerRoutesMock = jest.fn();
|
|||
jest.doMock('./routes', () => ({
|
||||
registerRoutes: registerRoutesMock,
|
||||
}));
|
||||
|
||||
export const createTagUsageCollectorMock = jest.fn();
|
||||
jest.doMock('./usage', () => ({
|
||||
createTagUsageCollector: createTagUsageCollectorMock,
|
||||
}));
|
||||
|
|
|
@ -4,20 +4,32 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { registerRoutesMock } from './plugin.test.mocks';
|
||||
import { registerRoutesMock, createTagUsageCollectorMock } from './plugin.test.mocks';
|
||||
|
||||
import { coreMock } from '../../../../src/core/server/mocks';
|
||||
import { featuresPluginMock } from '../../features/server/mocks';
|
||||
import { usageCollectionPluginMock } from '../../../../src/plugins/usage_collection/server/mocks';
|
||||
import { SavedObjectTaggingPlugin } from './plugin';
|
||||
import { savedObjectsTaggingFeature } from './features';
|
||||
|
||||
describe('SavedObjectTaggingPlugin', () => {
|
||||
let plugin: SavedObjectTaggingPlugin;
|
||||
let featuresPluginSetup: ReturnType<typeof featuresPluginMock.createSetup>;
|
||||
let usageCollectionSetup: ReturnType<typeof usageCollectionPluginMock.createSetupContract>;
|
||||
|
||||
beforeEach(() => {
|
||||
plugin = new SavedObjectTaggingPlugin(coreMock.createPluginInitializerContext());
|
||||
featuresPluginSetup = featuresPluginMock.createSetup();
|
||||
usageCollectionSetup = usageCollectionPluginMock.createSetupContract();
|
||||
// `usageCollection` 'mocked' implementation use the real `CollectorSet` implementation
|
||||
// that throws when registering things that are not collectors.
|
||||
// We just want to assert that it was called here, so jest.fn is fine.
|
||||
usageCollectionSetup.registerCollector = jest.fn();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
registerRoutesMock.mockReset();
|
||||
createTagUsageCollectorMock.mockReset();
|
||||
});
|
||||
|
||||
describe('#setup', () => {
|
||||
|
@ -43,5 +55,18 @@ describe('SavedObjectTaggingPlugin', () => {
|
|||
savedObjectsTaggingFeature
|
||||
);
|
||||
});
|
||||
|
||||
it('registers the usage collector if `usageCollection` is present', async () => {
|
||||
const tagUsageCollector = Symbol('saved_objects_tagging');
|
||||
createTagUsageCollectorMock.mockReturnValue(tagUsageCollector);
|
||||
|
||||
await plugin.setup(coreMock.createSetup(), {
|
||||
features: featuresPluginSetup,
|
||||
usageCollection: usageCollectionSetup,
|
||||
});
|
||||
|
||||
expect(usageCollectionSetup.registerCollector).toHaveBeenCalledTimes(1);
|
||||
expect(usageCollectionSetup.registerCollector).toHaveBeenCalledWith(tagUsageCollector);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,22 +4,36 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { CoreSetup, CoreStart, PluginInitializerContext, Plugin } from 'src/core/server';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
PluginInitializerContext,
|
||||
Plugin,
|
||||
SharedGlobalConfig,
|
||||
} from 'src/core/server';
|
||||
import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server';
|
||||
import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server';
|
||||
import { savedObjectsTaggingFeature } from './features';
|
||||
import { tagType } from './saved_objects';
|
||||
import { ITagsRequestHandlerContext } from './types';
|
||||
import { registerRoutes } from './routes';
|
||||
import { TagsRequestHandlerContext } from './request_handler_context';
|
||||
import { registerRoutes } from './routes';
|
||||
import { createTagUsageCollector } from './usage';
|
||||
|
||||
interface SetupDeps {
|
||||
features: FeaturesPluginSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
export class SavedObjectTaggingPlugin implements Plugin<{}, {}, SetupDeps, {}> {
|
||||
constructor(context: PluginInitializerContext) {}
|
||||
private readonly legacyConfig$: Observable<SharedGlobalConfig>;
|
||||
|
||||
public setup({ savedObjects, http }: CoreSetup, { features }: SetupDeps) {
|
||||
constructor(context: PluginInitializerContext) {
|
||||
this.legacyConfig$ = context.config.legacy.globalConfig$;
|
||||
}
|
||||
|
||||
public setup({ savedObjects, http }: CoreSetup, { features, usageCollection }: SetupDeps) {
|
||||
savedObjects.registerType(tagType);
|
||||
|
||||
const router = http.createRouter();
|
||||
|
@ -34,6 +48,15 @@ export class SavedObjectTaggingPlugin implements Plugin<{}, {}, SetupDeps, {}> {
|
|||
|
||||
features.registerKibanaFeature(savedObjectsTaggingFeature);
|
||||
|
||||
if (usageCollection) {
|
||||
usageCollection.registerCollector(
|
||||
createTagUsageCollector({
|
||||
usageCollection,
|
||||
legacyConfig$: this.legacyConfig$,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ElasticsearchClient } from 'src/core/server';
|
||||
import { TaggingUsageData, ByTypeTaggingUsageData } from './types';
|
||||
|
||||
/**
|
||||
* Manual type reflection of the `tagDataAggregations` resulting payload
|
||||
*/
|
||||
interface AggregatedTagUsageResponseBody {
|
||||
aggregations: {
|
||||
by_type: {
|
||||
buckets: Array<{
|
||||
key: string;
|
||||
doc_count: number;
|
||||
nested_ref: {
|
||||
tag_references: {
|
||||
doc_count: number;
|
||||
tag_id: {
|
||||
buckets: Array<{
|
||||
key: string;
|
||||
doc_count: number;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
};
|
||||
}>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const fetchTagUsageData = async ({
|
||||
esClient,
|
||||
kibanaIndex,
|
||||
}: {
|
||||
esClient: ElasticsearchClient;
|
||||
kibanaIndex: string;
|
||||
}): Promise<TaggingUsageData> => {
|
||||
const { body } = await esClient.search<AggregatedTagUsageResponseBody>({
|
||||
index: [kibanaIndex],
|
||||
ignore_unavailable: true,
|
||||
filter_path: 'aggregations',
|
||||
body: {
|
||||
size: 0,
|
||||
query: {
|
||||
bool: {
|
||||
must: [hasTagReferenceClause],
|
||||
},
|
||||
},
|
||||
aggs: tagDataAggregations,
|
||||
},
|
||||
});
|
||||
|
||||
const byTypeUsages: Record<string, ByTypeTaggingUsageData> = {};
|
||||
const allUsedTags = new Set<string>();
|
||||
let totalTaggedObjects = 0;
|
||||
|
||||
const typeBuckets = body.aggregations.by_type.buckets;
|
||||
typeBuckets.forEach((bucket) => {
|
||||
const type = bucket.key;
|
||||
const taggedDocCount = bucket.doc_count;
|
||||
const usedTagIds = bucket.nested_ref.tag_references.tag_id.buckets.map(
|
||||
(tagBucket) => tagBucket.key
|
||||
);
|
||||
|
||||
totalTaggedObjects += taggedDocCount;
|
||||
usedTagIds.forEach((tagId) => allUsedTags.add(tagId));
|
||||
|
||||
byTypeUsages[type] = {
|
||||
taggedObjects: taggedDocCount,
|
||||
usedTags: usedTagIds.length,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
usedTags: allUsedTags.size,
|
||||
taggedObjects: totalTaggedObjects,
|
||||
types: byTypeUsages,
|
||||
};
|
||||
};
|
||||
|
||||
const hasTagReferenceClause = {
|
||||
nested: {
|
||||
path: 'references',
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
term: {
|
||||
'references.type': 'tag',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const tagDataAggregations = {
|
||||
by_type: {
|
||||
terms: {
|
||||
field: 'type',
|
||||
},
|
||||
aggs: {
|
||||
nested_ref: {
|
||||
nested: {
|
||||
path: 'references',
|
||||
},
|
||||
aggs: {
|
||||
tag_references: {
|
||||
filter: {
|
||||
term: {
|
||||
'references.type': 'tag',
|
||||
},
|
||||
},
|
||||
aggs: {
|
||||
tag_id: {
|
||||
terms: {
|
||||
field: 'references.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { createTagUsageCollector } from './tag_usage_collector';
|
24
x-pack/plugins/saved_objects_tagging/server/usage/schema.ts
Normal file
24
x-pack/plugins/saved_objects_tagging/server/usage/schema.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { MakeSchemaFrom } from '../../../../../src/plugins/usage_collection/server';
|
||||
import { TaggingUsageData, ByTypeTaggingUsageData } from './types';
|
||||
|
||||
const perTypeSchema: MakeSchemaFrom<ByTypeTaggingUsageData> = {
|
||||
usedTags: { type: 'integer' },
|
||||
taggedObjects: { type: 'integer' },
|
||||
};
|
||||
|
||||
export const tagUsageCollectorSchema: MakeSchemaFrom<TaggingUsageData> = {
|
||||
usedTags: { type: 'integer' },
|
||||
taggedObjects: { type: 'integer' },
|
||||
|
||||
types: {
|
||||
dashboard: perTypeSchema,
|
||||
visualization: perTypeSchema,
|
||||
map: perTypeSchema,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { SharedGlobalConfig } from 'src/core/server';
|
||||
import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/server';
|
||||
import { TaggingUsageData } from './types';
|
||||
import { fetchTagUsageData } from './fetch_tag_usage_data';
|
||||
import { tagUsageCollectorSchema } from './schema';
|
||||
|
||||
export const createTagUsageCollector = ({
|
||||
usageCollection,
|
||||
legacyConfig$,
|
||||
}: {
|
||||
usageCollection: UsageCollectionSetup;
|
||||
legacyConfig$: Observable<SharedGlobalConfig>;
|
||||
}) => {
|
||||
return usageCollection.makeUsageCollector<TaggingUsageData>({
|
||||
type: 'saved_objects_tagging',
|
||||
isReady: () => true,
|
||||
schema: tagUsageCollectorSchema,
|
||||
fetch: async ({ esClient }) => {
|
||||
const { kibana } = await legacyConfig$.pipe(take(1)).toPromise();
|
||||
return fetchTagUsageData({ esClient, kibanaIndex: kibana.index });
|
||||
},
|
||||
});
|
||||
};
|
22
x-pack/plugins/saved_objects_tagging/server/usage/types.ts
Normal file
22
x-pack/plugins/saved_objects_tagging/server/usage/types.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface TaggingUsageData {
|
||||
usedTags: number;
|
||||
taggedObjects: number;
|
||||
types: Record<string, ByTypeTaggingUsageData>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface ByTypeTaggingUsageData {
|
||||
usedTags: number;
|
||||
taggedObjects: number;
|
||||
}
|
|
@ -1778,30 +1778,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"infraops": {
|
||||
"properties": {
|
||||
"last_24_hours": {
|
||||
"properties": {
|
||||
"hits": {
|
||||
"properties": {
|
||||
"infraops_hosts": {
|
||||
"type": "long"
|
||||
},
|
||||
"infraops_docker": {
|
||||
"type": "long"
|
||||
},
|
||||
"infraops_kubernetes": {
|
||||
"type": "long"
|
||||
},
|
||||
"logs": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ingest_manager": {
|
||||
"properties": {
|
||||
"fleet_enabled": {
|
||||
|
@ -1841,6 +1817,30 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"infraops": {
|
||||
"properties": {
|
||||
"last_24_hours": {
|
||||
"properties": {
|
||||
"hits": {
|
||||
"properties": {
|
||||
"infraops_hosts": {
|
||||
"type": "long"
|
||||
},
|
||||
"infraops_docker": {
|
||||
"type": "long"
|
||||
},
|
||||
"infraops_kubernetes": {
|
||||
"type": "long"
|
||||
},
|
||||
"logs": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"lens": {
|
||||
"properties": {
|
||||
"events_30_days": {
|
||||
|
@ -3136,6 +3136,50 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"saved_objects_tagging": {
|
||||
"properties": {
|
||||
"usedTags": {
|
||||
"type": "integer"
|
||||
},
|
||||
"taggedObjects": {
|
||||
"type": "integer"
|
||||
},
|
||||
"types": {
|
||||
"properties": {
|
||||
"dashboard": {
|
||||
"properties": {
|
||||
"usedTags": {
|
||||
"type": "integer"
|
||||
},
|
||||
"taggedObjects": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"visualization": {
|
||||
"properties": {
|
||||
"usedTags": {
|
||||
"type": "integer"
|
||||
},
|
||||
"taggedObjects": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"map": {
|
||||
"properties": {
|
||||
"usedTags": {
|
||||
"type": "integer"
|
||||
},
|
||||
"taggedObjects": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security_solution": {
|
||||
"properties": {
|
||||
"detections": {
|
||||
|
|
|
@ -40,7 +40,7 @@ export function UsageAPIProvider({ getService }: FtrProviderContext) {
|
|||
async getTelemetryStats(payload: {
|
||||
unencrypted?: boolean;
|
||||
timestamp: number | string;
|
||||
}): Promise<TelemetryCollectionManagerPlugin['getStats']> {
|
||||
}): Promise<ReturnType<TelemetryCollectionManagerPlugin['getStats']>> {
|
||||
const { body } = await supertest
|
||||
.post('/api/telemetry/v2/clusters/_stats')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
|
|
|
@ -14,5 +14,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
|
|||
loadTestFile(require.resolve('./delete'));
|
||||
loadTestFile(require.resolve('./create'));
|
||||
loadTestFile(require.resolve('./update'));
|
||||
loadTestFile(require.resolve('./usage_collection'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import { FtrProviderContext } from '../services';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const usageAPI = getService('usageAPI');
|
||||
|
||||
describe('saved_object_tagging usage collector data', () => {
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load('usage_collection');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await esArchiver.unload('usage_collection');
|
||||
});
|
||||
|
||||
/*
|
||||
* Dataset description:
|
||||
*
|
||||
* 5 tags: tag-1 tag-2 tag-3 tag-4 ununsed-tag
|
||||
* 3 dashboard:
|
||||
* - dash-1: ref to tag-1 + tag-2
|
||||
* - dash-2: ref to tag-2 + tag 4
|
||||
* - dash-3: no ref to any tag
|
||||
* 3 visualization:
|
||||
* - vis-1: ref to tag-1
|
||||
* - vis-2: ref to tag-1 + tag-3
|
||||
* - vis-3: ref to tag-3
|
||||
*/
|
||||
it('collects the expected data', async () => {
|
||||
const telemetryStats = (await usageAPI.getTelemetryStats({
|
||||
unencrypted: true,
|
||||
timestamp: Date.now(),
|
||||
})) as any;
|
||||
|
||||
const taggingStats = telemetryStats[0].stack_stats.kibana.plugins.saved_objects_tagging;
|
||||
expect(taggingStats).to.eql({
|
||||
usedTags: 4,
|
||||
taggedObjects: 5,
|
||||
types: {
|
||||
dashboard: {
|
||||
taggedObjects: 2,
|
||||
usedTags: 3,
|
||||
},
|
||||
visualization: {
|
||||
taggedObjects: 3,
|
||||
usedTags: 2,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,313 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "space:default",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"space": {
|
||||
"_reserved": true,
|
||||
"description": "This is the default space",
|
||||
"name": "Default Space"
|
||||
},
|
||||
"type": "space",
|
||||
"updated_at": "2017-09-21T18:49:16.270Z"
|
||||
},
|
||||
"type": "doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "tag:tag-1",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"tag": {
|
||||
"name": "tag-1",
|
||||
"description": "My first tag!",
|
||||
"color": "#FF00FF"
|
||||
},
|
||||
"type": "tag",
|
||||
"updated_at": "2017-09-21T18:49:16.270Z"
|
||||
},
|
||||
"type": "doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "tag:tag-2",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"tag": {
|
||||
"name": "tag-2",
|
||||
"description": "Another awesome tag",
|
||||
"color": "#FFFFFF"
|
||||
},
|
||||
"type": "tag",
|
||||
"updated_at": "2017-09-21T18:49:16.270Z"
|
||||
},
|
||||
"type": "doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "tag:tag-3",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"tag": {
|
||||
"name": "tag-3",
|
||||
"description": "Last but not least",
|
||||
"color": "#000000"
|
||||
},
|
||||
"type": "tag",
|
||||
"updated_at": "2017-09-21T18:49:16.270Z"
|
||||
},
|
||||
"type": "doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "tag:tag-4",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"tag": {
|
||||
"name": "tag-4",
|
||||
"description": "Last",
|
||||
"color": "#000000"
|
||||
},
|
||||
"type": "tag",
|
||||
"updated_at": "2017-09-21T18:49:16.270Z"
|
||||
},
|
||||
"type": "doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "tag:unused-tag",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"tag": {
|
||||
"name": "unused-tag",
|
||||
"description": "This tag is unused and should only appear in totalTags",
|
||||
"color": "#123456"
|
||||
},
|
||||
"type": "tag",
|
||||
"updated_at": "2017-09-21T18:49:16.270Z"
|
||||
},
|
||||
"type": "doc"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"index": ".kibana",
|
||||
"id": "visualization:ref-to-tag-1",
|
||||
"source": {
|
||||
"type": "visualization",
|
||||
"updated_at": "2017-09-21T18:51:23.794Z",
|
||||
"visualization": {
|
||||
"title": "Vis with ref to tag-1",
|
||||
"visState": "{}",
|
||||
"uiStateJSON": "{\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
|
||||
}
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "tag",
|
||||
"id": "tag-1",
|
||||
"name": "tag-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"index": ".kibana",
|
||||
"id": "visualization:ref-to-tag-1-and-tag-3",
|
||||
"source": {
|
||||
"type": "visualization",
|
||||
"updated_at": "2017-09-21T18:51:23.794Z",
|
||||
"visualization": {
|
||||
"title": "Vis with ref to tag-1 and tag-2",
|
||||
"visState": "{}",
|
||||
"uiStateJSON": "{\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
|
||||
}
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "tag",
|
||||
"id": "tag-1",
|
||||
"name": "tag-1"
|
||||
},
|
||||
{
|
||||
"type": "tag",
|
||||
"id": "tag-3",
|
||||
"name": "tag-3"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"index": ".kibana",
|
||||
"id": "visualization:ref-to-tag-3",
|
||||
"source": {
|
||||
"type": "visualization",
|
||||
"updated_at": "2017-09-21T18:51:23.794Z",
|
||||
"visualization": {
|
||||
"title": "Vis with ref to tag-2",
|
||||
"visState": "{}",
|
||||
"uiStateJSON": "{\"spy\":{\"mode\":{\"name\":null,\"fill\":false}}}",
|
||||
"description": "",
|
||||
"version": 1,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
|
||||
}
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"type": "tag",
|
||||
"id": "tag-3",
|
||||
"name": "tag-3"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "dashboard:ref-to-tag-1-and-tag-2",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"dashboard": {
|
||||
"title": "dashboard 1 (tag-2)",
|
||||
"description": "",
|
||||
"hits": 0,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"negate\":false,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"animal\",\"value\":\"dog\",\"params\":{\"query\":\"dog\",\"type\":\"phrase\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"animal\":{\"query\":\"dog\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}],\"highlightAll\":true,\"version\":true}"
|
||||
},
|
||||
"optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}",
|
||||
"panelsJSON": "[]",
|
||||
"timeFrom": "Mon Apr 09 2018 17:56:08 GMT-0400",
|
||||
"timeRestore": true,
|
||||
"timeTo": "Wed Apr 11 2018 17:56:08 GMT-0400",
|
||||
"version": 1
|
||||
},
|
||||
"migrationVersion": {
|
||||
"dashboard": "7.3.0"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"id": "tag-1",
|
||||
"name": "tag-1-ref",
|
||||
"type": "tag"
|
||||
},
|
||||
{
|
||||
"id": "tag-2",
|
||||
"name": "tag-2-ref",
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"type": "dashboard",
|
||||
"updated_at": "2018-04-11T21:57:52.253Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "dashboard:ref-to-tag-2-and-tag-4",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"dashboard": {
|
||||
"title": "dashboard 2 (tag-2 and tag-4)",
|
||||
"description": "",
|
||||
"hits": 0,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"negate\":false,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"animal\",\"value\":\"dog\",\"params\":{\"query\":\"dog\",\"type\":\"phrase\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"animal\":{\"query\":\"dog\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}],\"highlightAll\":true,\"version\":true}"
|
||||
},
|
||||
"optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}",
|
||||
"panelsJSON": "[]",
|
||||
"timeFrom": "Mon Apr 09 2018 17:56:08 GMT-0400",
|
||||
"timeRestore": true,
|
||||
"timeTo": "Wed Apr 11 2018 17:56:08 GMT-0400",
|
||||
"version": 1
|
||||
},
|
||||
"migrationVersion": {
|
||||
"dashboard": "7.3.0"
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"id": "tag-2",
|
||||
"name": "tag-2-ref",
|
||||
"type": "tag"
|
||||
},
|
||||
{
|
||||
"id": "tag-4",
|
||||
"name": "tag-4-ref",
|
||||
"type": "tag"
|
||||
}
|
||||
],
|
||||
"type": "dashboard",
|
||||
"updated_at": "2018-04-11T21:57:52.253Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "dashboard:no-tag-reference",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"dashboard": {
|
||||
"title": "dashboard 2 (tag-2 and tag-4)",
|
||||
"description": "",
|
||||
"hits": 0,
|
||||
"kibanaSavedObjectMeta": {
|
||||
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[{\"meta\":{\"negate\":false,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"animal\",\"value\":\"dog\",\"params\":{\"query\":\"dog\",\"type\":\"phrase\"},\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"match\":{\"animal\":{\"query\":\"dog\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}],\"highlightAll\":true,\"version\":true}"
|
||||
},
|
||||
"optionsJSON": "{\"darkTheme\":false,\"useMargins\":true,\"hidePanelTitles\":false}",
|
||||
"panelsJSON": "[]",
|
||||
"timeFrom": "Mon Apr 09 2018 17:56:08 GMT-0400",
|
||||
"timeRestore": true,
|
||||
"timeTo": "Wed Apr 11 2018 17:56:08 GMT-0400",
|
||||
"version": 1
|
||||
},
|
||||
"migrationVersion": {
|
||||
"dashboard": "7.3.0"
|
||||
},
|
||||
"references": [
|
||||
],
|
||||
"type": "dashboard",
|
||||
"updated_at": "2018-04-11T21:57:52.253Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {},
|
||||
"index": ".kibana",
|
||||
"mappings": {
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"config": {
|
||||
"dynamic": "true",
|
||||
"properties": {
|
||||
"buildNum": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"defaultIndex": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"migrationVersion": {
|
||||
"dynamic": "true",
|
||||
"properties": {
|
||||
"dashboard": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"index-pattern": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"search": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"visualization": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"dynamic": "strict",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"hits": {
|
||||
"type": "integer"
|
||||
},
|
||||
"kibanaSavedObjectMeta": {
|
||||
"properties": {
|
||||
"searchSourceJSON": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"optionsJSON": {
|
||||
"type": "text"
|
||||
},
|
||||
"panelsJSON": {
|
||||
"type": "text"
|
||||
},
|
||||
"refreshInterval": {
|
||||
"properties": {
|
||||
"display": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"pause": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"section": {
|
||||
"type": "integer"
|
||||
},
|
||||
"value": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeFrom": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"timeRestore": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"timeTo": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"uiStateJSON": {
|
||||
"type": "text"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"index-pattern": {
|
||||
"properties": {
|
||||
"fieldFormatMap": {
|
||||
"type": "text"
|
||||
},
|
||||
"fields": {
|
||||
"type": "text"
|
||||
},
|
||||
"intervalName": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"notExpandable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sourceFilters": {
|
||||
"type": "text"
|
||||
},
|
||||
"timeFieldName": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"namespace": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"namespaces": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"originId": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"server": {
|
||||
"properties": {
|
||||
"uuid": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tag": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "text"
|
||||
},
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"color": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"space": {
|
||||
"properties": {
|
||||
"_reserved": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"color": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"disabledFeatures": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"initials": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"name": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 2048,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"references": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "nested"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"visualization": {
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "text"
|
||||
},
|
||||
"kibanaSavedObjectMeta": {
|
||||
"properties": {
|
||||
"searchSourceJSON": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"savedSearchId": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"title": {
|
||||
"type": "text"
|
||||
},
|
||||
"uiStateJSON": {
|
||||
"type": "text"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
},
|
||||
"visState": {
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"auto_expand_replicas": "0-1",
|
||||
"number_of_replicas": "0",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue