Skip to content

Commit

Permalink
support legacy client for data source
Browse files Browse the repository at this point in the history
Signed-off-by: Su <[email protected]>
  • Loading branch information
zhongnansu committed Aug 25, 2022
1 parent abd159b commit bc8fc37
Show file tree
Hide file tree
Showing 14 changed files with 341 additions and 86 deletions.
2 changes: 1 addition & 1 deletion src/core/server/opensearch/legacy/cluster_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const noop = () => undefined;
* OpenSearch JS client.
* @param options Options that affect the way we call the API and process the result.
*/
const callAPI = async (
export const callAPI = async (
client: Client,
endpoint: string,
clientParams: Record<string, any> = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* under the License.
*/

import { LegacyAPICaller, OpenSearchClient } from 'opensearch-dashboards/server';
import { LegacyAPICaller } from 'opensearch-dashboards/server';

import { getFieldCapabilities, resolveTimePattern, createNoMatchingIndicesError } from './lib';

Expand All @@ -48,9 +48,9 @@ interface FieldSubType {
}

export class IndexPatternsFetcher {
private _callDataCluster: LegacyAPICaller | OpenSearchClient;
private _callDataCluster: LegacyAPICaller;

constructor(callDataCluster: LegacyAPICaller | OpenSearchClient) {
constructor(callDataCluster: LegacyAPICaller) {
this._callDataCluster = callDataCluster;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import { defaults, keyBy, sortBy } from 'lodash';

import { LegacyAPICaller, OpenSearchClient } from 'opensearch-dashboards/server';
import { LegacyAPICaller } from 'opensearch-dashboards/server';
import { callFieldCapsApi } from '../opensearch_api';
import { FieldCapsResponse, readFieldCapsResponse } from './field_caps_response';
import { mergeOverrides } from './overrides';
Expand All @@ -47,7 +47,7 @@ import { FieldDescriptor } from '../../index_patterns_fetcher';
* @return {Promise<Array<FieldDescriptor>>}
*/
export async function getFieldCapabilities(
callCluster: LegacyAPICaller | OpenSearchClient,
callCluster: LegacyAPICaller,
indices: string | string[] = [],
metaFields: string[] = [],
fieldCapsOptions?: { allowNoIndices: boolean }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,22 +94,11 @@ export async function callIndexAliasApi(
* @return {Promise<FieldCapsResponse>}
*/
export async function callFieldCapsApi(
callCluster: LegacyAPICaller | OpenSearchClient,
callCluster: LegacyAPICaller,
indices: string[] | string,
fieldCapsOptions: { allowNoIndices: boolean } = { allowNoIndices: false }
) {
try {
if ('transport' in callCluster) {
return (
await callCluster.fieldCaps({
index: indices,
fields: '*',
ignore_unavailable: true,
allow_no_indices: fieldCapsOptions.allowNoIndices,
})
).body as FieldCapsResponse;
}

return (await callCluster('fieldCaps', {
index: indices,
fields: '*',
Expand Down
15 changes: 9 additions & 6 deletions src/plugins/data/server/index_patterns/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
*/

import { schema } from '@osd/config-schema';
import { HttpServiceSetup, RequestHandlerContext } from 'opensearch-dashboards/server';
import {
HttpServiceSetup,
LegacyAPICaller,
RequestHandlerContext,
} from 'opensearch-dashboards/server';
import { IndexPatternsFetcher } from './fetcher';

export function registerRoutes(http: HttpServiceSetup) {
Expand Down Expand Up @@ -153,9 +157,8 @@ export function registerRoutes(http: HttpServiceSetup) {

const decideClient = async (context: RequestHandlerContext, request: any) => {
const dataSourceId = request.query.data_source;
if (dataSourceId) {
return await context.dataSource.opensearch.getClient(dataSourceId);
}

return context.core.opensearch.legacy.client.callAsCurrentUser;
return dataSourceId
? ((await context.dataSource.opensearch.legacy.getClient(dataSourceId)
.callAPI) as LegacyAPICaller)
: context.core.opensearch.legacy.client.callAsCurrentUser;
};
15 changes: 8 additions & 7 deletions src/plugins/data_source/server/client/client_pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
*/

import { Client } from '@opensearch-project/opensearch';
import { Client as LegacyClient } from 'elasticsearch';
import LRUCache from 'lru-cache';
import { Logger } from 'src/core/server';
import { DataSourcePluginConfigType } from '../../config';

export interface OpenSearchClientPoolSetup {
getClientFromPool: (id: string) => Client | undefined;
addClientToPool: (endpoint: string, client: Client) => void;
getClientFromPool: (id: string) => Client | LegacyClient | undefined;
addClientToPool: (endpoint: string, client: Client | LegacyClient) => void;
}

/**
Expand All @@ -21,14 +22,14 @@ export interface OpenSearchClientPoolSetup {
*/
export class OpenSearchClientPool {
// LRU cache
// key: data source endpoint url
// value: OpenSearch client object
private cache?: LRUCache<string, Client>;
// key: data source endpoint, prefixed with identifier for legacy
// value: OpenSearch client object | Legacy client object
private cache?: LRUCache<string, Client | LegacyClient>;
private isClosed = false;

constructor(private logger: Logger) {}

public async setup(config: DataSourcePluginConfigType) {
public async setup(config: DataSourcePluginConfigType): Promise<OpenSearchClientPoolSetup> {
const logger = this.logger;
const { size } = config.clientPool;

Expand All @@ -53,7 +54,7 @@ export class OpenSearchClientPool {
return this.cache!.get(endpoint);
};

const addClientToPool = (endpoint: string, client: Client) => {
const addClientToPool = (endpoint: string, client: Client | LegacyClient) => {
this.cache!.set(endpoint, client);
};

Expand Down
54 changes: 44 additions & 10 deletions src/plugins/data_source/server/client/configure_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { Client } from '@opensearch-project/opensearch';
import {
Logger,
LegacyAPICaller,
SavedObject,
SavedObjectsClientContract,
SavedObjectsErrorHelpers,
Expand All @@ -18,17 +18,18 @@ import {
import { DataSourceAttributes } from '../../common/data_sources';
import { DataSourcePluginConfigType } from '../../config';
import { CryptographyClient } from '../cryptography';
import { DataSourceClientParams } from '../types';
import { parseClientOptions } from './client_config';
import { OpenSearchClientPoolSetup } from './client_pool';

export const configureClient = async (
dataSourceId: string,
savedObjects: SavedObjectsClientContract,
cryptographyClient: CryptographyClient,
openSearchClientPoolSetup: OpenSearchClientPoolSetup,
config: DataSourcePluginConfigType,
logger: Logger
): Promise<Client> => {
export const configureClient = async ({
dataSourceId,
savedObjects,
config,
logger,
cryptographyClient,
openSearchClientPoolSetup,
}: DataSourceClientParams): Promise<Client> => {
const dataSource = await getDataSource(dataSourceId, savedObjects);
const rootClient = getRootClient(dataSource.attributes, config, openSearchClientPoolSetup);

Expand Down Expand Up @@ -120,7 +121,7 @@ const getRootClient = (
const endpoint = dataSourceAttr.endpoint;
const cachedClient = getClientFromPool(endpoint);
if (cachedClient) {
return cachedClient;
return cachedClient as Client;
} else {
const clientOptions = parseClientOptions(config, endpoint);

Expand All @@ -147,3 +148,36 @@ const getBasicAuthClient = (
headers: { authorization: null },
});
};

// const getLegacyClient = (client: Client, isLegacy: boolean, logger: Logger): Client => {
// if (isLegacy) {
// logger.warn(
// 'Legacy OpenSearch client is used. Please migrate your code to use the new OpenSearch client.'
// );
// return new LegacyScopedClusterClient(callAsCurrentUser, callAsCurrentUser);
// } else {
// return client;
// }
// };

/**
* Calls specified endpoint with provided clientParams on behalf of the
* user initiated request to the OpenSearch Dashboards server (via HTTP request headers).
* See {@link LegacyAPICaller}.
*
* @param endpoint - String descriptor of the endpoint e.g. `cluster.getSettings` or `ping`.
* @param clientParams - A dictionary of parameters that will be passed directly to the OpenSearch JS client.
* @param options - Options that affect the way we call the API and process the result.
*/
// const callAsCurrentUser: LegacyAPICaller = async (
// client: Client,
// endpoint: string,
// clientParams: Record<string, any> = {},
// options?: LegacyCallAPIOptions
// ) => {
// return await (callAPI.bind(null, client as EsClient) as LegacyAPICaller)(
// endpoint,
// clientParams,
// options
// );
// };
82 changes: 61 additions & 21 deletions src/plugins/data_source/server/data_source_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,42 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { Logger, OpenSearchClient, SavedObjectsClientContract } from '../../../../src/core/server';
import {
LegacyCallAPIOptions,
Logger,
OpenSearchClient,
SavedObjectsClientContract,
} from '../../../../src/core/server';
import { DataSourcePluginConfigType } from '../config';
import { OpenSearchClientPool, configureClient } from './client';
import { CryptographyClient } from './cryptography';
import { configureLegacyClient } from './legacy';

export interface LegacyClientCallAPIParams {
endpoint: string;
clientParams?: Record<string, any>;
options?: LegacyCallAPIOptions;
}

export interface DataSourceClientParams {
dataSourceId: string;
// this saved objects client is used to fetch data source on behalf of users, caller should pass scoped saved objects client
savedObjects: SavedObjectsClientContract;
cryptographyClient: CryptographyClient;
}

export interface DataSourceServiceSetup {
getDataSourceClient: (
dataSourceId: string,
// this saved objects client is used to fetch data source on behalf of users, caller should pass scoped saved objects client
savedObjects: SavedObjectsClientContract,
cryptographyClient: CryptographyClient
) => Promise<OpenSearchClient>;
getDataSourceClient: (params: DataSourceClientParams) => Promise<OpenSearchClient>;

getDataSourceLegacyClient: (
params: DataSourceClientParams
) => {
callAPI: (
endpoint: string,
clientParams?: Record<string, any>,
options?: LegacyCallAPIOptions
) => Promise<any>;
};
}
export class DataSourceService {
private readonly openSearchClientPool: OpenSearchClientPool;
Expand All @@ -22,25 +47,40 @@ export class DataSourceService {
this.openSearchClientPool = new OpenSearchClientPool(logger);
}

async setup(config: DataSourcePluginConfigType) {
const openSearchClientPoolSetup = await this.openSearchClientPool.setup(config);
async setup(config: DataSourcePluginConfigType): Promise<DataSourceServiceSetup> {
const basicParams = {
openSearchClientPoolSetup: await this.openSearchClientPool.setup(config),
config,
logger: this.logger,
};

const getDataSourceClient = async (
dataSourceId: string,
savedObjects: SavedObjectsClientContract,
cryptographyClient: CryptographyClient
dataSourceClientParams: DataSourceClientParams
): Promise<OpenSearchClient> => {
return configureClient(
dataSourceId,
savedObjects,
cryptographyClient,
openSearchClientPoolSetup,
config,
this.logger
);
return configureClient({
...basicParams,
...dataSourceClientParams,
});
};

const getDataSourceLegacyClient = (dataSourceClientParams: DataSourceClientParams) => {
return {
callAPI: (
endpoint: string,
clientParams?: Record<string, any>,
options?: LegacyCallAPIOptions
) =>
configureLegacyClient(
{
...basicParams,
...dataSourceClientParams,
},
{ endpoint, clientParams, options }
),
};
};

return { getDataSourceClient };
return { getDataSourceClient, getDataSourceLegacyClient };
}

start() {}
Expand Down
28 changes: 28 additions & 0 deletions src/plugins/data_source/server/legacy/client_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { ConfigOptions } from 'elasticsearch';
import { DataSourcePluginConfigType } from '../../config';

/**
* Parse the client options from given data source config and endpoint
*
* @param config The config to generate the client options from.
* @param endpoint endpoint url of data source
*/
export function parseClientOptions(
// TODO: will use client configs, that comes from a merge result of user config and default legacy client config,
config: DataSourcePluginConfigType,
endpoint: string
): ConfigOptions {
const configOptions: ConfigOptions = {
host: endpoint,
ssl: {
rejectUnauthorized: true,
},
};

return configOptions;
}
Loading

0 comments on commit bc8fc37

Please sign in to comment.