Skip to content

Commit

Permalink
[Snapshot Restore] Migrate to new ES client (elastic#95499)
Browse files Browse the repository at this point in the history
* wip, migrated routes and plugins

* refactored all ES error handling to use handleEsError and new isEsError detection

* - fixed Jest tests for new es client
- updated routes in light of new responses

* remove unused import

* remove unecessary isEsError check in rest api route handlers

* mute all incorrect types from client lib using @ts-expect-error

* reordered and clean up imports, removed legacy client code

* update legacy test runner

* updated use of legacyES

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
# Conflicts:
#	x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts
#	x-pack/plugins/snapshot_restore/server/routes/api/snapshots.test.ts
#	x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts
  • Loading branch information
jloleysens committed Mar 31, 2021
1 parent 91f31cf commit 2040d74
Show file tree
Hide file tree
Showing 21 changed files with 456 additions and 691 deletions.
101 changes: 0 additions & 101 deletions x-pack/plugins/snapshot_restore/server/client/elasticsearch_sr.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,24 @@
* 2.0.
*/

import type { ElasticsearchClient } from 'src/core/server';

// Cloud has its own system for managing SLM policies and we want to make
// this clear when Snapshot and Restore is used in a Cloud deployment.
// Retrieve the Cloud-managed policies so that UI can switch
// logical paths based on this information.
export const getManagedPolicyNames = async (callWithInternalUser: any): Promise<string[]> => {
export const getManagedPolicyNames = async (
clusterClient: ElasticsearchClient
): Promise<string[]> => {
try {
const { persistent, transient, defaults } = await callWithInternalUser('cluster.getSettings', {
filterPath: '*.*managed_policies',
flatSettings: true,
includeDefaults: true,
const {
body: { persistent, transient, defaults },
} = await clusterClient.cluster.getSettings({
filter_path: '*.*managed_policies',
flat_settings: true,
include_defaults: true,
});

const { 'cluster.metadata.managed_policies': managedPolicyNames = [] } = {
...defaults,
...persistent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@
* 2.0.
*/

import type { ElasticsearchClient } from 'src/core/server';

// Cloud has its own system for managing snapshots and we want to make
// this clear when Snapshot and Restore is used in a Cloud deployment.
// Retrieve the Cloud-managed repository name so that UI can switch
// logical paths based on this information.
export const getManagedRepositoryName = async (
callWithInternalUser: any
client: ElasticsearchClient
): Promise<string | undefined> => {
try {
const { persistent, transient, defaults } = await callWithInternalUser('cluster.getSettings', {
filterPath: '*.*managed_repository',
flatSettings: true,
includeDefaults: true,
const {
body: { persistent, transient, defaults },
} = await client.cluster.getSettings({
filter_path: '*.*managed_repository',
flat_settings: true,
include_defaults: true,
});
const { 'cluster.metadata.managed_repository': managedRepositoryName = undefined } = {
...defaults,
Expand Down
41 changes: 5 additions & 36 deletions x-pack/plugins/snapshot_restore/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,20 @@
*/

import { i18n } from '@kbn/i18n';
import {
CoreSetup,
ILegacyCustomClusterClient,
Plugin,
Logger,
PluginInitializerContext,
} from 'kibana/server';
import { CoreSetup, Plugin, Logger, PluginInitializerContext } from 'kibana/server';

import { PLUGIN, APP_REQUIRED_CLUSTER_PRIVILEGES } from '../common';
import { License } from './services';
import { ApiRoutes } from './routes';
import { wrapEsError } from './lib';
import { isEsError } from './shared_imports';
import { elasticsearchJsPlugin } from './client/elasticsearch_sr';
import type { Dependencies, SnapshotRestoreRequestHandlerContext } from './types';
import { handleEsError } from './shared_imports';
import type { Dependencies } from './types';
import { SnapshotRestoreConfig } from './config';

async function getCustomEsClient(getStartServices: CoreSetup['getStartServices']) {
const [core] = await getStartServices();
const esClientConfig = { plugins: [elasticsearchJsPlugin] };
return core.elasticsearch.legacy.createClient('snapshotRestore', esClientConfig);
}

export class SnapshotRestoreServerPlugin implements Plugin<void, void, any, any> {
private readonly logger: Logger;
private readonly apiRoutes: ApiRoutes;
private readonly license: License;
private snapshotRestoreESClient?: ILegacyCustomClusterClient;

constructor(private context: PluginInitializerContext) {
const { logger } = this.context;
Expand All @@ -52,7 +38,7 @@ export class SnapshotRestoreServerPlugin implements Plugin<void, void, any, any>
return;
}

const router = http.createRouter<SnapshotRestoreRequestHandlerContext>();
const router = http.createRouter();

this.license.setup(
{
Expand Down Expand Up @@ -82,17 +68,6 @@ export class SnapshotRestoreServerPlugin implements Plugin<void, void, any, any>
],
});

http.registerRouteHandlerContext<SnapshotRestoreRequestHandlerContext, 'snapshotRestore'>(
'snapshotRestore',
async (ctx, request) => {
this.snapshotRestoreESClient =
this.snapshotRestoreESClient ?? (await getCustomEsClient(getStartServices));
return {
client: this.snapshotRestoreESClient.asScoped(request),
};
}
);

this.apiRoutes.setup({
router,
license: this.license,
Expand All @@ -102,17 +77,11 @@ export class SnapshotRestoreServerPlugin implements Plugin<void, void, any, any>
isSlmEnabled: pluginConfig.slm_ui.enabled,
},
lib: {
isEsError,
handleEsError,
wrapEsError,
},
});
}

public start() {}

public stop() {
if (this.snapshotRestoreESClient) {
this.snapshotRestoreESClient.close();
}
}
}
59 changes: 23 additions & 36 deletions x-pack/plugins/snapshot_restore/server/routes/api/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ export function registerAppRoutes({
router,
config: { isSecurityEnabled },
license,
lib: { isEsError },
lib: { handleEsError },
}: RouteDependencies) {
router.get(
{ path: addBasePath('privileges'), validate: false },
license.guardApiRoute(async (ctx, req, res) => {
const { callAsCurrentUser } = ctx.snapshotRestore!.client;
const { client: clusterClient } = ctx.core.elasticsearch;

const privilegesResult: Privileges = {
hasAllPrivileges: true,
Expand All @@ -48,42 +48,36 @@ export function registerAppRoutes({
}

try {
// Get cluster priviliges
const { has_all_requested: hasAllPrivileges, cluster } = await callAsCurrentUser(
'transport.request',
{
path: '/_security/user/_has_privileges',
method: 'POST',
body: {
cluster: [...APP_REQUIRED_CLUSTER_PRIVILEGES, ...APP_SLM_CLUSTER_PRIVILEGES],
},
}
);
// Get cluster privileges
const {
body: { has_all_requested: hasAllPrivileges, cluster },
} = await clusterClient.asCurrentUser.security.hasPrivileges({
body: {
cluster: [...APP_REQUIRED_CLUSTER_PRIVILEGES, ...APP_SLM_CLUSTER_PRIVILEGES],
},
});

// Find missing cluster privileges and set overall app privileges
privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(cluster);
privilegesResult.hasAllPrivileges = hasAllPrivileges;

// Get all index privileges the user has
const { indices } = await callAsCurrentUser('transport.request', {
path: '/_security/user/_privileges',
method: 'GET',
});
const {
body: { indices },
} = await clusterClient.asCurrentUser.security.getUserPrivileges();

// Check if they have all the required index privileges for at least one index
const oneIndexWithAllPrivileges = indices.find(
({ privileges }: { privileges: string[] }) => {
if (privileges.includes('all')) {
return true;
}
const oneIndexWithAllPrivileges = indices.find(({ privileges }) => {
if (privileges.includes('all')) {
return true;
}

const indexHasAllPrivileges = APP_RESTORE_INDEX_PRIVILEGES.every((privilege) =>
privileges.includes(privilege)
);
const indexHasAllPrivileges = APP_RESTORE_INDEX_PRIVILEGES.every((privilege) =>
privileges.includes(privilege)
);

return indexHasAllPrivileges;
}
);
return indexHasAllPrivileges;
});

// If they don't, return list of required index privileges
if (!oneIndexWithAllPrivileges) {
Expand All @@ -92,14 +86,7 @@ export function registerAppRoutes({

return res.ok({ body: privilegesResult });
} catch (e) {
if (isEsError(e)) {
return res.customError({
statusCode: e.statusCode,
body: e,
});
}
// Case: default
throw e;
return handleEsError({ error: e, response: res });
}
})
);
Expand Down
Loading

0 comments on commit 2040d74

Please sign in to comment.