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

[6.x] Saved Object Namespaces (#23378) #23536

Merged
merged 1 commit into from
Sep 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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