Skip to content

Commit

Permalink
[MD]Improve datasource error handling
Browse files Browse the repository at this point in the history
Signed-off-by: Su <[email protected]>
  • Loading branch information
zhongnansu committed Sep 1, 2022
1 parent 7fefb05 commit d4d30f8
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 51 deletions.
12 changes: 12 additions & 0 deletions src/core/server/http/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,23 @@ export class Router implements IRouter {
if (LegacyOpenSearchErrorHelpers.isNotAuthorizedError(e)) {
return e;
}

if (isDataSourceConfigError(e)) {
return hapiResponseAdapter.handle(
opensearchDashboardsResponseFactory.badRequest({ body: e.message })
);
}
// TODO: add legacy data source client config error handling

return hapiResponseAdapter.toInternalError();
}
}
}

const isDataSourceConfigError = (error: any) => {
return error.constructor.name === 'DataSourceConfigError';
};

const convertOpenSearchUnauthorized = (
e: OpenSearchNotAuthorizedError
): ErrorHttpResponseOptions => {
Expand Down
56 changes: 24 additions & 32 deletions src/plugins/data_source/server/client/configure_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,16 @@
*/

import { Client } from '@opensearch-project/opensearch';
import {
Logger,
SavedObject,
SavedObjectsClientContract,
SavedObjectsErrorHelpers,
} from '../../../../../src/core/server';
import { Logger, SavedObject, SavedObjectsClientContract } from '../../../../../src/core/server';
import { DATA_SOURCE_SAVED_OBJECT_TYPE } from '../../common';

import {
AuthType,
DataSourceAttributes,
UsernamePasswordTypedContent,
} from '../../common/data_sources';
import { DataSourcePluginConfigType } from '../../config';
import { CryptographyClient } from '../cryptography';
import { DataSourceConfigError } from '../lib/error';
import { parseClientOptions } from './client_config';
import { OpenSearchClientPoolSetup } from './client_pool';

Expand All @@ -30,45 +25,42 @@ export const configureClient = async (
config: DataSourcePluginConfigType,
logger: Logger
): Promise<Client> => {
const dataSource = await getDataSource(dataSourceId, savedObjects);
const rootClient = getRootClient(dataSource.attributes, config, openSearchClientPoolSetup);
try {
const dataSource = await getDataSource(dataSourceId, savedObjects);
const rootClient = getRootClient(dataSource.attributes, config, openSearchClientPoolSetup);

return getQueryClient(rootClient, dataSource, cryptographyClient);
return await getQueryClient(rootClient, dataSource, cryptographyClient);
} catch (error: any) {
logger.error(`Fail to get data source client for dataSourceId: [${dataSourceId}]`);
logger.error(error);
// Re-throw as DataSourceConfigError
throw new DataSourceConfigError('Fail to get data source client: ', error);
}
};

export const getDataSource = async (
dataSourceId: string,
savedObjects: SavedObjectsClientContract
): Promise<SavedObject<DataSourceAttributes>> => {
try {
const dataSource = await savedObjects.get<DataSourceAttributes>(
DATA_SOURCE_SAVED_OBJECT_TYPE,
dataSourceId
);
return dataSource;
} catch (error: any) {
// it will cause 500 error when failed to get saved objects, need to handle such error gracefully
throw SavedObjectsErrorHelpers.createBadRequestError(error.message);
}
const dataSource = await savedObjects.get<DataSourceAttributes>(
DATA_SOURCE_SAVED_OBJECT_TYPE,
dataSourceId
);
return dataSource;
};

export const getCredential = async (
dataSource: SavedObject<DataSourceAttributes>,
cryptographyClient: CryptographyClient
): Promise<UsernamePasswordTypedContent> => {
try {
const { username, password } = dataSource.attributes.auth.credentials!;
const decodedPassword = await cryptographyClient.decodeAndDecrypt(password);
const credential = {
username,
password: decodedPassword,
};
const { username, password } = dataSource.attributes.auth.credentials!;
const decodedPassword = await cryptographyClient.decodeAndDecrypt(password);
const credential = {
username,
password: decodedPassword,
};

return credential;
} catch (error: any) {
// it will cause 500 error when failed to get saved objects, need to handle such error gracefully
throw SavedObjectsErrorHelpers.createBadRequestError(error.message);
}
return credential;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/data_source/server/data_source_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class DataSourceService {
async setup(config: DataSourcePluginConfigType) {
const openSearchClientPoolSetup = await this.openSearchClientPool.setup(config);

const getDataSourceClient = async (
const getDataSourceClient = (
dataSourceId: string,
savedObjects: SavedObjectsClientContract,
cryptographyClient: CryptographyClient
Expand Down
15 changes: 15 additions & 0 deletions src/plugins/data_source/server/lib/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import Boom from '@hapi/boom';
import { OsdError } from '../../../../../src/plugins/opensearch_dashboards_utils/common';

export class DataSourceConfigError extends OsdError {
statusCode = 400;
constructor(messagePrefix: string, e: any) {
const messageContent = Boom.isBoom(e) ? e.output.payload.message : e.message;
super(messagePrefix + messageContent);
}
}
24 changes: 8 additions & 16 deletions src/plugins/data_source/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { OpenSearchClientError } from '@opensearch-project/opensearch/lib/errors';
import { Observable } from 'rxjs';
import { first, map } from 'rxjs/operators';
import {
Expand Down Expand Up @@ -129,21 +128,14 @@ export class DataSourcePlugin implements Plugin<DataSourcePluginSetup, DataSourc
return {
opensearch: {
getClient: (dataSourceId: string) => {
try {
const auditor = auditTrailPromise.then((auditTrail) => auditTrail.asScoped(req));
this.logAuditMessage(auditor, dataSourceId, req);

return dataSourceService.getDataSourceClient(
dataSourceId,
context.core.savedObjects.client,
cryptographyClient
);
} catch (error: any) {
logger.error(
`Fail to get data source client for dataSourceId: [${dataSourceId}]. Detail: ${error.messages}`
);
throw new OpenSearchClientError(error.message);
}
const auditor = auditTrailPromise.then((auditTrail) => auditTrail.asScoped(req));
this.logAuditMessage(auditor, dataSourceId, req);

return dataSourceService.getDataSourceClient(
dataSourceId,
context.core.savedObjects.client,
cryptographyClient
);
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export async function getIndices({
pattern,
showAllIndices,
dataSourceId,
}).catch(() => []);
});
requests.push(promiseResolve);

if (isCCS) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ export function registerResolveIndexRoute(router: IRouter): void {
});
return res.ok({ body: result.body });
}

const result = await context.core.opensearch.legacy.client.callAsCurrentUser(
'transport.request',
{
Expand Down

0 comments on commit d4d30f8

Please sign in to comment.