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

[7.x] Add support for sharing saved objects to all spaces (#76132) #79411

Merged
merged 2 commits into from
Oct 5, 2020
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
4 changes: 4 additions & 0 deletions docs/api/saved-objects/bulk_create.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ experimental[] Create multiple {kib} saved objects.
`references`::
(Optional, array) Objects with `name`, `id`, and `type` properties that describe the other saved objects in the referenced object. To refer to the other saved object, use `name` in the attributes. Never use `id` to refer to the other saved object. `id` can be automatically updated during migrations, import, or export.

`namespaces`::
(Optional, string array) Identifiers for the <<xpack-spaces,spaces>> in which this object should be created. If this is not provided, the
object will be created in the current space.

`version`::
(Optional, number) Specifies the version.

Expand Down
4 changes: 4 additions & 0 deletions docs/api/saved-objects/create.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ any data that you send to the API is properly formed.
`references`::
(Optional, array) Objects with `name`, `id`, and `type` properties that describe the other saved objects that this object references. Use `name` in attributes to refer to the other saved object, but never the `id`, which can update automatically during migrations or import/export.

`namespaces`::
(Optional, string array) Identifiers for the <<xpack-spaces,spaces>> in which this object should be created. If this is not provided, the
object will be created in the current space.

[[saved-objects-api-create-request-codes]]
==== Response code

Expand Down
8 changes: 8 additions & 0 deletions docs/api/saved-objects/delete.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ WARNING: Once you delete a saved object, _it cannot be recovered_.
`id`::
(Required, string) The object ID that you want to remove.

[[saved-objects-api-delete-query-params]]
==== Query parameters

`force`::
(Optional, boolean) When true, forces an object to be deleted if it exists in multiple namespaces.
+
TIP: Use this if you attempted to delete an object and received an HTTP 400 error with the following message: _"Unable to delete saved object that exists in multiple namespaces, use the `force` option to delete it anyway"_

[[saved-objects-api-delete-response-codes]]
==== Response code

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ Deletes an object
<b>Signature:</b>

```typescript
delete: (type: string, id: string) => ReturnType<SavedObjectsApi['delete']>;
delete: (type: string, id: string, options?: SavedObjectsDeleteOptions | undefined) => ReturnType<SavedObjectsApi['delete']>;
```
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The constructor for this class is marked as internal. Third-party code should no
| [bulkCreate](./kibana-plugin-core-public.savedobjectsclient.bulkcreate.md) | | <code>(objects?: SavedObjectsBulkCreateObject[], options?: SavedObjectsBulkCreateOptions) =&gt; Promise&lt;SavedObjectsBatchResponse&lt;unknown&gt;&gt;</code> | Creates multiple documents at once |
| [bulkGet](./kibana-plugin-core-public.savedobjectsclient.bulkget.md) | | <code>(objects?: Array&lt;{</code><br/><code> id: string;</code><br/><code> type: string;</code><br/><code> }&gt;) =&gt; Promise&lt;SavedObjectsBatchResponse&lt;unknown&gt;&gt;</code> | Returns an array of objects by id |
| [create](./kibana-plugin-core-public.savedobjectsclient.create.md) | | <code>&lt;T = unknown&gt;(type: string, attributes: T, options?: SavedObjectsCreateOptions) =&gt; Promise&lt;SimpleSavedObject&lt;T&gt;&gt;</code> | Persists an object |
| [delete](./kibana-plugin-core-public.savedobjectsclient.delete.md) | | <code>(type: string, id: string) =&gt; ReturnType&lt;SavedObjectsApi['delete']&gt;</code> | Deletes an object |
| [delete](./kibana-plugin-core-public.savedobjectsclient.delete.md) | | <code>(type: string, id: string, options?: SavedObjectsDeleteOptions &#124; undefined) =&gt; ReturnType&lt;SavedObjectsApi['delete']&gt;</code> | Deletes an object |
| [find](./kibana-plugin-core-public.savedobjectsclient.find.md) | | <code>&lt;T = unknown&gt;(options: SavedObjectsFindOptions) =&gt; Promise&lt;SavedObjectsFindResponsePublic&lt;T&gt;&gt;</code> | Search for objects |
| [get](./kibana-plugin-core-public.savedobjectsclient.get.md) | | <code>&lt;T = unknown&gt;(type: string, id: string) =&gt; Promise&lt;SimpleSavedObject&lt;T&gt;&gt;</code> | Fetches a single object |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface SavedObjectsBulkCreateObject<T = unknown>
| [attributes](./kibana-plugin-core-server.savedobjectsbulkcreateobject.attributes.md) | <code>T</code> | |
| [id](./kibana-plugin-core-server.savedobjectsbulkcreateobject.id.md) | <code>string</code> | |
| [migrationVersion](./kibana-plugin-core-server.savedobjectsbulkcreateobject.migrationversion.md) | <code>SavedObjectsMigrationVersion</code> | Information about the migrations that have been applied to this SavedObject. When Kibana starts up, KibanaMigrator detects outdated documents and migrates them based on this value. For each migration that has been applied, the plugin's name is used as a key and the latest migration version as the value. |
| [namespaces](./kibana-plugin-core-server.savedobjectsbulkcreateobject.namespaces.md) | <code>string[]</code> | Optional initial namespaces for the object to be created in. If this is defined, it will supersede the namespace ID that is in [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md)<!-- -->.<!-- -->Note: this can only be used for multi-namespace object types. |
| [originId](./kibana-plugin-core-server.savedobjectsbulkcreateobject.originid.md) | <code>string</code> | Optional ID of the original saved object, if this object's <code>id</code> was regenerated |
| [references](./kibana-plugin-core-server.savedobjectsbulkcreateobject.references.md) | <code>SavedObjectReference[]</code> | |
| [type](./kibana-plugin-core-server.savedobjectsbulkcreateobject.type.md) | <code>string</code> | |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsBulkCreateObject](./kibana-plugin-core-server.savedobjectsbulkcreateobject.md) &gt; [namespaces](./kibana-plugin-core-server.savedobjectsbulkcreateobject.namespaces.md)

## SavedObjectsBulkCreateObject.namespaces property

Optional initial namespaces for the object to be created in. If this is defined, it will supersede the namespace ID that is in [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md)<!-- -->.

Note: this can only be used for multi-namespace object types.

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface SavedObjectsCreateOptions extends SavedObjectsBaseOptions
| --- | --- | --- |
| [id](./kibana-plugin-core-server.savedobjectscreateoptions.id.md) | <code>string</code> | (not recommended) Specify an id for the document |
| [migrationVersion](./kibana-plugin-core-server.savedobjectscreateoptions.migrationversion.md) | <code>SavedObjectsMigrationVersion</code> | Information about the migrations that have been applied to this SavedObject. When Kibana starts up, KibanaMigrator detects outdated documents and migrates them based on this value. For each migration that has been applied, the plugin's name is used as a key and the latest migration version as the value. |
| [namespaces](./kibana-plugin-core-server.savedobjectscreateoptions.namespaces.md) | <code>string[]</code> | Optional initial namespaces for the object to be created in. If this is defined, it will supersede the namespace ID that is in [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md)<!-- -->.<!-- -->Note: this can only be used for multi-namespace object types. |
| [originId](./kibana-plugin-core-server.savedobjectscreateoptions.originid.md) | <code>string</code> | Optional ID of the original saved object, if this object's <code>id</code> was regenerated |
| [overwrite](./kibana-plugin-core-server.savedobjectscreateoptions.overwrite.md) | <code>boolean</code> | Overwrite existing documents (defaults to false) |
| [references](./kibana-plugin-core-server.savedobjectscreateoptions.references.md) | <code>SavedObjectReference[]</code> | |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md) &gt; [namespaces](./kibana-plugin-core-server.savedobjectscreateoptions.namespaces.md)

## SavedObjectsCreateOptions.namespaces property

Optional initial namespaces for the object to be created in. If this is defined, it will supersede the namespace ID that is in [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md)<!-- -->.

Note: this can only be used for multi-namespace object types.

<b>Signature:</b>

```typescript
namespaces?: string[];
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectsDeleteOptions](./kibana-plugin-core-server.savedobjectsdeleteoptions.md) &gt; [force](./kibana-plugin-core-server.savedobjectsdeleteoptions.force.md)

## SavedObjectsDeleteOptions.force property

Force deletion of an object that exists in multiple namespaces

<b>Signature:</b>

```typescript
force?: boolean;
```
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ export interface SavedObjectsDeleteOptions extends SavedObjectsBaseOptions

| Property | Type | Description |
| --- | --- | --- |
| [force](./kibana-plugin-core-server.savedobjectsdeleteoptions.force.md) | <code>boolean</code> | Force deletion of an object that exists in multiple namespaces |
| [refresh](./kibana-plugin-core-server.savedobjectsdeleteoptions.refresh.md) | <code>MutatingOperationRefreshSetting</code> | The Elasticsearch Refresh setting for this operation |

3 changes: 2 additions & 1 deletion src/core/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1030,8 +1030,9 @@ export class SavedObjectsClient {
}>) => Promise<SavedObjectsBatchResponse<unknown>>;
bulkUpdate<T = unknown>(objects?: SavedObjectsBulkUpdateObject[]): Promise<SavedObjectsBatchResponse<unknown>>;
create: <T = unknown>(type: string, attributes: T, options?: SavedObjectsCreateOptions) => Promise<SimpleSavedObject<T>>;
// Warning: (ae-forgotten-export) The symbol "SavedObjectsDeleteOptions" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "SavedObjectsClientContract" needs to be exported by the entry point index.d.ts
delete: (type: string, id: string) => ReturnType<SavedObjectsClientContract_2['delete']>;
delete: (type: string, id: string, options?: SavedObjectsDeleteOptions | undefined) => ReturnType<SavedObjectsClientContract_2['delete']>;
// Warning: (ae-forgotten-export) The symbol "SavedObjectsFindOptions" needs to be exported by the entry point index.d.ts
find: <T = unknown>(options: SavedObjectsFindOptions_2) => Promise<SavedObjectsFindResponsePublic<T>>;
get: <T = unknown>(type: string, id: string) => Promise<SimpleSavedObject<T>>;
Expand Down
4 changes: 3 additions & 1 deletion src/core/public/saved_objects/saved_objects_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ describe('SavedObjectsClient', () => {
Object {
"body": undefined,
"method": "DELETE",
"query": undefined,
"query": Object {
"force": false,
},
},
]
`);
Expand Down
18 changes: 16 additions & 2 deletions src/core/public/saved_objects/saved_objects_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ export interface SavedObjectsBatchResponse<T = unknown> {
savedObjects: Array<SimpleSavedObject<T>>;
}

/** @public */
export interface SavedObjectsDeleteOptions {
/** Force deletion of an object that exists in multiple namespaces */
force?: boolean;
}

/**
* Return type of the Saved Objects `find()` method.
*
Expand Down Expand Up @@ -261,12 +267,20 @@ export class SavedObjectsClient {
* @param id
* @returns
*/
public delete = (type: string, id: string): ReturnType<SavedObjectsApi['delete']> => {
public delete = (
type: string,
id: string,
options?: SavedObjectsDeleteOptions
): ReturnType<SavedObjectsApi['delete']> => {
if (!type || !id) {
return Promise.reject(new Error('requires type and id'));
}

return this.savedObjectsFetch(this.getPath([type, id]), { method: 'DELETE' });
const query = {
force: !!options?.force,
};

return this.savedObjectsFetch(this.getPath([type, id]), { method: 'DELETE', query });
};

/**
Expand Down
1 change: 1 addition & 0 deletions src/core/server/saved_objects/routes/bulk_create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const registerBulkCreateRoute = (router: IRouter) => {
})
)
),
namespaces: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })),
})
),
},
Expand Down
5 changes: 3 additions & 2 deletions src/core/server/saved_objects/routes/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,16 @@ export const registerCreateRoute = (router: IRouter) => {
})
)
),
namespaces: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })),
}),
},
},
router.handleLegacyErrors(async (context, req, res) => {
const { type, id } = req.params;
const { overwrite } = req.query;
const { attributes, migrationVersion, references } = req.body;
const { attributes, migrationVersion, references, namespaces } = req.body;

const options = { id, overwrite, migrationVersion, references };
const options = { id, overwrite, migrationVersion, references, namespaces };
const result = await context.core.savedObjects.client.create(type, attributes, options);
return res.ok({ body: result });
})
Expand Down
6 changes: 5 additions & 1 deletion src/core/server/saved_objects/routes/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ export const registerDeleteRoute = (router: IRouter) => {
type: schema.string(),
id: schema.string(),
}),
query: schema.object({
force: schema.maybe(schema.boolean()),
}),
},
},
router.handleLegacyErrors(async (context, req, res) => {
const { type, id } = req.params;
const result = await context.core.savedObjects.client.delete(type, id);
const { force } = req.query;
const result = await context.core.savedObjects.client.delete(type, id, { force });
return res.ok({ body: result });
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ describe('DELETE /api/saved_objects/{type}/{id}', () => {
.delete('/api/saved_objects/index-pattern/logstash-*')
.expect(200);

expect(savedObjectsClient.delete).toHaveBeenCalledWith('index-pattern', 'logstash-*');
expect(savedObjectsClient.delete).toHaveBeenCalledWith('index-pattern', 'logstash-*', {
force: undefined,
});
});

it('can specify `force` option', async () => {
await supertest(httpSetup.server.listener)
.delete('/api/saved_objects/index-pattern/logstash-*')
.query({ force: true })
.expect(200);

expect(savedObjectsClient.delete).toHaveBeenCalledWith('index-pattern', 'logstash-*', {
force: true,
});
});
});
Loading