Skip to content
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

Saved Object Namespaces #23378

Merged
merged 20 commits into from
Sep 26, 2018
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a3b3168
Use an instance of SavedObjectsSerializer for migrations and the repo…
kobelb Sep 18, 2018
04ed13d
Fixing spelling of serialization
kobelb Sep 18, 2018
d406c61
Making the serializer conditionally include and prepend id with ns
kobelb Sep 19, 2018
7b87f0a
Adding repository tests for the namespaces
kobelb Sep 19, 2018
f2a2f46
Implementing find
kobelb Sep 20, 2018
8c314f5
Modifying the SOCs to pass the options with the namespace
kobelb Sep 20, 2018
93c6b79
Centralizing omitting the namespace when using serializer.rawToSavedO…
kobelb Sep 20, 2018
ba43a69
Passing the schema through to the SavedObjectRepositoryProvider
kobelb Sep 20, 2018
954d9df
Changing the schema to work with undefined ui exports schemas
kobelb Sep 20, 2018
a293000
Adding schema tests
kobelb Sep 20, 2018
86edf75
Making the complimentary serialization test use the namespace
kobelb Sep 20, 2018
f54a294
Fixing uiExports
kobelb Sep 20, 2018
40eeab6
Merge remote-tracking branch 'upstream/master' into saved-object-name…
kobelb Sep 20, 2018
3e20cda
Fixing some tests
kobelb Sep 20, 2018
1350708
Fixing included fields for the find
kobelb Sep 20, 2018
1c3b481
Fixing include field tests, they're checking length also...
kobelb Sep 20, 2018
493f899
Updating Repository test after adding namespace to always included
kobelb Sep 21, 2018
fbf87ed
Renaming UIExportsSavedObjectTypeSchema to SavedObjectsSchemaDefinition
kobelb Sep 25, 2018
d47fede
Completing rename... forgot to save usages
kobelb Sep 25, 2018
0db2f73
Fixing issue with the serialization.isRawSavedObject and the trailing :
kobelb Sep 26, 2018
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Object {
"dynamic": "true",
"type": "object",
},
"namespace": Object {
"type": "keyword",
},
"type": Object {
"type": "keyword",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ function defaultMapping(): IndexMapping {
type: {
type: 'keyword',
},
namespace: {
type: 'keyword',
},
updated_at: {
type: 'date',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

import _ from 'lodash';
import sinon from 'sinon';
import { ROOT_TYPE, SavedObjectDoc } from '../../serialization';
import { SavedObjectsSchema } from '../../schema';
import { ROOT_TYPE, SavedObjectDoc, SavedObjectsSerializer } from '../../serialization';
import { CallCluster } from './call_cluster';
import { IndexMigrator } from './index_migrator';

Expand All @@ -46,6 +47,7 @@ describe('IndexMigrator', () => {
},
foo: { type: 'text' },
migrationVersion: { dynamic: 'true', type: 'object' },
namespace: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
},
Expand Down Expand Up @@ -78,6 +80,7 @@ describe('IndexMigrator', () => {
},
foo: { type: 'long' },
migrationVersion: { dynamic: 'true', type: 'object' },
namespace: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
},
Expand Down Expand Up @@ -188,6 +191,7 @@ describe('IndexMigrator', () => {
},
foo: { type: 'text' },
migrationVersion: { dynamic: 'true', type: 'object' },
namespace: { type: 'keyword' },
type: { type: 'keyword' },
updated_at: { type: 'date' },
},
Expand Down Expand Up @@ -301,6 +305,7 @@ function defaultOpts() {
migrationVersion: {},
migrate: _.identity,
},
serializer: new SavedObjectsSerializer(new SavedObjectsSchema()),
};
}

Expand Down
8 changes: 6 additions & 2 deletions src/server/saved_objects/migrations/core/index_migrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ async function migrateIndex(context: Context): Promise<MigrationResult> {
*/
async function migrateSourceToDest(context: Context) {
const { callCluster, alias, dest, source, batchSize } = context;
const { scrollDuration, documentMigrator, log } = context;
const { scrollDuration, documentMigrator, log, serializer } = context;

if (!source.exists) {
return;
Expand All @@ -174,6 +174,10 @@ async function migrateSourceToDest(context: Context) {

log.debug(`Migrating saved objects ${docs.map(d => d._id).join(', ')}`);

await Index.write(callCluster, dest.indexName, migrateRawDocs(documentMigrator.migrate, docs));
await Index.write(
callCluster,
dest.indexName,
migrateRawDocs(serializer, documentMigrator.migrate, docs)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@

import _ from 'lodash';
import sinon from 'sinon';
import { ROOT_TYPE } from '../../serialization';
import { SavedObjectsSchema } from '../../schema';
import { ROOT_TYPE, SavedObjectsSerializer } from '../../serialization';
import { migrateRawDocs } from './migrate_raw_docs';

describe('migrateRawDocs', () => {
test('converts raw docs to saved objects', async () => {
const transform = sinon.spy((doc: any) => _.set(doc, 'attributes.name', 'HOI!'));
const result = migrateRawDocs(transform, [
const result = migrateRawDocs(new SavedObjectsSerializer(new SavedObjectsSchema()), transform, [
{ _id: 'a:b', _source: { type: 'a', a: { name: 'AAA' } } },
{ _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } },
]);
Expand All @@ -48,7 +49,7 @@ describe('migrateRawDocs', () => {

test('passes invalid docs through untouched', async () => {
const transform = sinon.spy((doc: any) => _.set(_.cloneDeep(doc), 'attributes.name', 'TADA'));
const result = migrateRawDocs(transform, [
const result = migrateRawDocs(new SavedObjectsSerializer(new SavedObjectsSchema()), transform, [
{ _id: 'foo:b', _source: { type: 'a', a: { name: 'AAA' } } },
{ _id: 'c:d', _source: { type: 'c', c: { name: 'DDD' } } },
]);
Expand Down
14 changes: 9 additions & 5 deletions src/server/saved_objects/migrations/core/migrate_raw_docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* This file provides logic for migrating raw documents.
*/

import { isRawSavedObject, RawDoc, rawToSavedObject, savedObjectToRaw } from '../../serialization';
import { RawDoc, SavedObjectsSerializer } from '../../serialization';
import { TransformFn } from './document_migrator';

/**
Expand All @@ -32,12 +32,16 @@ import { TransformFn } from './document_migrator';
* @param {RawDoc[]} rawDocs
* @returns {RawDoc[]}
*/
export function migrateRawDocs(migrateDoc: TransformFn, rawDocs: RawDoc[]): RawDoc[] {
export function migrateRawDocs(
serializer: SavedObjectsSerializer,
migrateDoc: TransformFn,
rawDocs: RawDoc[]
): RawDoc[] {
return rawDocs.map(raw => {
if (isRawSavedObject(raw)) {
const savedObject = rawToSavedObject(raw);
if (serializer.isRawSavedObject(raw)) {
const savedObject = serializer.rawToSavedObject(raw);
savedObject.migrationVersion = savedObject.migrationVersion || {};
return savedObjectToRaw(migrateDoc(savedObject));
return serializer.savedObjectToRaw(migrateDoc(savedObject));
}

return raw;
Expand Down
4 changes: 4 additions & 0 deletions src/server/saved_objects/migrations/core/migration_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* serves as a central blueprint for what migrations will end up doing.
*/

import { SavedObjectsSerializer } from '../../serialization';
import { buildActiveMappings } from './build_active_mappings';
import { CallCluster, MappingProperties } from './call_cluster';
import { VersionedTransformer } from './document_migrator';
Expand All @@ -39,6 +40,7 @@ export interface MigrationOpts {
log: LogFn;
mappingProperties: MappingProperties;
documentMigrator: VersionedTransformer;
serializer: SavedObjectsSerializer;
}

export interface Context {
Expand All @@ -51,6 +53,7 @@ export interface Context {
batchSize: number;
pollInterval: number;
scrollDuration: string;
serializer: SavedObjectsSerializer;
}

/**
Expand All @@ -74,6 +77,7 @@ export async function migrationContext(opts: MigrationOpts): Promise<Context> {
documentMigrator: opts.documentMigrator,
pollInterval: opts.pollInterval,
scrollDuration: opts.scrollDuration,
serializer: opts.serializer,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Object {
"dynamic": "true",
"type": "object",
},
"namespace": Object {
"type": "keyword",
},
"type": Object {
"type": "keyword",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ function mockKbnServer({ configValues }: { configValues?: any } = {}) {
savedObjectValidations: {},
savedObjectMigrations: {},
savedObjectMappings: [],
savedObjectSchemas: {},
},
server: {
config: () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
* (the shape of the mappings and documents in the index).
*/

import { SavedObjectDoc } from '../../serialization';
import { SavedObjectsSchema, SavedObjectsSchemaDefinition } from '../../schema';
import { SavedObjectDoc, SavedObjectsSerializer } from '../../serialization';
import { docValidator } from '../../validation';
import { buildActiveMappings, CallCluster, IndexMigrator, LogFn, MappingProperties } from '../core';
import { DocumentMigrator, VersionedTransformer } from '../core/document_migrator';
Expand All @@ -34,6 +35,7 @@ export interface KbnServer {
savedObjectMappings: any[];
savedObjectMigrations: any;
savedObjectValidations: any;
savedObjectSchemas: SavedObjectsSchemaDefinition;
};
}

Expand Down Expand Up @@ -64,6 +66,7 @@ export class KibanaMigrator {
private documentMigrator: VersionedTransformer;
private mappingProperties: MappingProperties;
private log: LogFn;
private serializer: SavedObjectsSerializer;

/**
* Creates an instance of KibanaMigrator.
Expand All @@ -74,6 +77,9 @@ export class KibanaMigrator {
*/
constructor({ kbnServer }: { kbnServer: KbnServer }) {
this.kbnServer = kbnServer;
this.serializer = new SavedObjectsSerializer(
new SavedObjectsSchema(kbnServer.uiExports.savedObjectSchemas)
);
this.mappingProperties = mergeProperties(kbnServer.uiExports.savedObjectMappings || []);
this.log = (meta: string[], message: string) => kbnServer.server.log(meta, message);
this.documentMigrator = new DocumentMigrator({
Expand Down Expand Up @@ -133,6 +139,7 @@ export class KibanaMigrator {
mappingProperties: this.mappingProperties,
pollInterval: config.get('migrations.pollInterval'),
scrollDuration: config.get('migrations.scrollDuration'),
serializer: this.serializer,
});

return migrator.migrate();
Expand Down
6 changes: 5 additions & 1 deletion src/server/saved_objects/saved_objects_mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import { createSavedObjectsService } from './service';
import { KibanaMigrator } from './migrations';
import { SavedObjectsSchema } from './schema';
import { SavedObjectsSerializer } from './serialization';

import {
createBulkCreateRoute,
Expand Down Expand Up @@ -62,7 +64,9 @@ export function savedObjectsMixin(kbnServer, server) {
server.route(createGetRoute(prereqs));
server.route(createUpdateRoute(prereqs));

server.decorate('server', 'savedObjects', createSavedObjectsService(server, migrator));
const schema = new SavedObjectsSchema(kbnServer.uiExports.savedObjectSchemas);
const serializer = new SavedObjectsSerializer(schema);
server.decorate('server', 'savedObjects', createSavedObjectsService(server, schema, serializer, migrator));

const savedObjectsClientCache = new WeakMap();
server.decorate('request', 'getSavedObjectsClient', function () {
Expand Down
20 changes: 20 additions & 0 deletions src/server/saved_objects/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/

export { SavedObjectsSchema, SavedObjectsSchemaDefinition } from './schema';
48 changes: 48 additions & 0 deletions src/server/saved_objects/schema/schema.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/

import { SavedObjectsSchema } from './schema';

describe('#isNamespaceAgnostic', () => {
it(`returns false for unknown types`, () => {
const schema = new SavedObjectsSchema();
const result = schema.isNamespaceAgnostic('bar');
expect(result).toBe(false);
});

it(`returns true for explicitly namespace agnostic type`, () => {
const schema = new SavedObjectsSchema({
foo: {
isNamespaceAgnostic: true,
},
});
const result = schema.isNamespaceAgnostic('foo');
expect(result).toBe(true);
});

it(`returns false for explicitly namespaced type`, () => {
const schema = new SavedObjectsSchema({
foo: {
isNamespaceAgnostic: false,
},
});
const result = schema.isNamespaceAgnostic('foo');
expect(result).toBe(false);
});
});
47 changes: 47 additions & 0 deletions src/server/saved_objects/schema/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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.
*/

interface SavedObjectsSchemaTypeDefinition {
isNamespaceAgnostic: boolean;
}

export interface SavedObjectsSchemaDefinition {
[key: string]: SavedObjectsSchemaTypeDefinition;
}

export class SavedObjectsSchema {
private readonly definition?: SavedObjectsSchemaDefinition;
constructor(schemaDefinition?: SavedObjectsSchemaDefinition) {
this.definition = schemaDefinition;
}

public isNamespaceAgnostic(type: string) {
// if no plugins have registered a uiExports.savedObjectSchemas,
// this.schema will be undefined, and no types are namespace agnostic
if (!this.definition) {
return false;
}

const typeSchema = this.definition[type];
if (!typeSchema) {
return false;
}
return Boolean(typeSchema.isNamespaceAgnostic);
}
}
Loading