Skip to content

Commit

Permalink
Merge branch '2.x' into backport/backport-5946-to-2.x
Browse files Browse the repository at this point in the history
  • Loading branch information
abbyhu2000 authored Feb 27, 2024
2 parents 2ab61bd + f6bbeb4 commit 404ff4d
Show file tree
Hide file tree
Showing 28 changed files with 574 additions and 76 deletions.
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

### Deprecations

### 🛡 Security

### 📈 Features/Enhancements

### 🐛 Bug Fixes

### 🚞 Infrastructure

### 📝 Documentation

### 🛠 Maintenance

### 🪛 Refactoring

### 🔩 Tests

## [2.12.0 - 2024-02-20](https://github.com/opensearch-project/OpenSearch-Dashboards/releases/tag/2.12.0)

### 💥 Breaking Changes

### Deprecations

- Rename `withLongNumerals` to `withLongNumeralsSupport` in `HttpFetchOptions` [#5592](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5592)

### 🛡 Security
Expand Down Expand Up @@ -38,6 +60,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Multiple Datasource] Add interfaces to register add-on authentication method from plug-in module ([#5851](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5851))
- [Multiple Datasource] Able to Hide "Local Cluster" option from datasource DropDown ([#5827](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5827))
- [Multiple Datasource] Add api registry and allow it to be added into client config in data source plugin ([#5895](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5895))
- [Multiple Datasource] Refactor client and legacy client to use authentication registry ([#5881](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5881))

### 🐛 Bug Fixes

Expand All @@ -58,6 +81,8 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Discover] Fix missing index pattern field from breaking Discover [#5626](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5626)
- [BUG] Remove duplicate sample data as id 90943e30-9a47-11e8-b64d-95841ca0b247 ([5668](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5668))
- [BUG][Multiple Datasource] Fix datasource testing connection unexpectedly passed with wrong endpoint [#5663](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5663)
- [BUG][Multiple Datasource] Fix missing customApiRegistryPromise param for test connection ([#5944](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5944))


### 🚞 Infrastructure

Expand All @@ -84,7 +109,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Replace `node-sass` with `sass-embedded` ([#5338](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5338))
- Bump `chromedriver` from `107.0.3` to `119.0.1` ([#5465](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5465))
- Bump `typescript` resolution from `4.0.2` to `4.6.4` ([#5470](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5470))
- Bump `OUI` to `1.4.0` ([#5637](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5637))
- Bump `OUI` to `1.5.1` ([#5862](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5862))
- Add @SuZhou-Joe as a maintainer ([#5594](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5594))
- Move @seanneumann to emeritus maintainer ([#5634](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5634))
- Remove `ui-select` dev dependency ([#5660](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5660))
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
"dependencies": {
"@aws-crypto/client-node": "^3.1.1",
"@elastic/datemath": "5.0.3",
"@elastic/eui": "npm:@opensearch-project/oui@1.4.0",
"@elastic/eui": "npm:@opensearch-project/oui@1.5.1",
"@elastic/good": "^9.0.1-kibana3",
"@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0",
"@elastic/request-crypto": "2.0.0",
Expand Down Expand Up @@ -474,4 +474,4 @@
"node": ">=14.20.1 <19",
"yarn": "^1.22.10"
}
}
}
2 changes: 1 addition & 1 deletion packages/osd-ui-framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"enzyme-adapter-react-16": "^1.9.1"
},
"devDependencies": {
"@elastic/eui": "npm:@opensearch-project/oui@1.4.0",
"@elastic/eui": "npm:@opensearch-project/oui@1.5.1",
"@osd/babel-preset": "1.0.0",
"@osd/optimizer": "1.0.0",
"comment-stripper": "^0.0.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/osd-ui-shared-deps/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@elastic/charts": "31.1.0",
"@elastic/eui": "npm:@opensearch-project/oui@1.4.0",
"@elastic/eui": "npm:@opensearch-project/oui@1.5.1",
"@elastic/numeral": "npm:@amoo-miki/numeral@2.6.0",
"@opensearch/datemath": "5.0.3",
"@osd/i18n": "1.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ export const decideClient = async (
request: IOpenSearchSearchRequest,
withLongNumeralsSupport: boolean = false
): Promise<OpenSearchClient> => {
// if data source feature is disabled, return default opensearch client of current user
const client =
request.dataSourceId && context.dataSource
? await context.dataSource.opensearch.getClient(request.dataSourceId)
: withLongNumeralsSupport
? context.core.opensearch.client.asCurrentUserWithLongNumeralsSupport
: context.core.opensearch.client.asCurrentUser;
return client;
const defaultOpenSearchClient = withLongNumeralsSupport
? context.core.opensearch.client.asCurrentUserWithLongNumeralsSupport
: context.core.opensearch.client.asCurrentUser;

return request.dataSourceId && context.dataSource
? await context.dataSource.opensearch.getClient(request.dataSourceId)
: defaultOpenSearchClient;
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,47 @@
*/

import { RequestHandlerContext } from '../../../../../core/server';
import { pluginInitializerContextConfigMock } from '../../../../../core/server/mocks';
import {
opensearchServiceMock,
pluginInitializerContextConfigMock,
} from '../../../../../core/server/mocks';
import { opensearchSearchStrategyProvider } from './opensearch_search_strategy';
import { DataSourceError } from '../../../../data_source/server/lib/error';
import { DataSourcePluginSetup } from '../../../../data_source/server';
import { SearchUsage } from '../collectors';

describe('OpenSearch search strategy', () => {
const mockLogger: any = {
debug: () => {},
};
const mockSearchUsage: SearchUsage = {
trackError(): Promise<void> {
return Promise.resolve(undefined);
},
trackSuccess(duration: number): Promise<void> {
return Promise.resolve(undefined);
},
};
const mockDataSourcePluginSetupWithDataSourceEnabled: DataSourcePluginSetup = {
createDataSourceError(err: any): DataSourceError {
return new DataSourceError({});
},
dataSourceEnabled: jest.fn(() => true),
registerCredentialProvider: jest.fn(),
registerCustomApiSchema(schema: any): void {
throw new Error('Function not implemented.');
},
};
const mockDataSourcePluginSetupWithDataSourceDisabled: DataSourcePluginSetup = {
createDataSourceError(err: any): DataSourceError {
return new DataSourceError({});
},
dataSourceEnabled: jest.fn(() => false),
registerCredentialProvider: jest.fn(),
registerCustomApiSchema(schema: any): void {
throw new Error('Function not implemented.');
},
};
const body = {
body: {
_shards: {
Expand All @@ -50,6 +82,7 @@ describe('OpenSearch search strategy', () => {
};
const mockOpenSearchApiCaller = jest.fn().mockResolvedValue(body);
const mockDataSourceApiCaller = jest.fn().mockResolvedValue(body);
const mockOpenSearchApiCallerWithLongNumeralsSupport = jest.fn().mockResolvedValue(body);
const dataSourceId = 'test-data-source-id';
const mockDataSourceContext = {
dataSource: {
Expand All @@ -67,7 +100,14 @@ describe('OpenSearch search strategy', () => {
get: () => {},
},
},
opensearch: { client: { asCurrentUser: { search: mockOpenSearchApiCaller } } },
opensearch: {
client: {
asCurrentUser: { search: mockOpenSearchApiCaller },
asCurrentUserWithLongNumeralsSupport: {
search: mockOpenSearchApiCallerWithLongNumeralsSupport,
},
},
},
},
};
const mockDataSourceEnabledContext = {
Expand Down Expand Up @@ -131,20 +171,110 @@ describe('OpenSearch search strategy', () => {
expect(response).toHaveProperty('rawResponse');
});

it('dataSource enabled, send request with dataSourceId get data source client', async () => {
const opensearchSearch = await opensearchSearchStrategyProvider(mockConfig$, mockLogger);
it('dataSource enabled, config host exist, send request with dataSourceId should get data source client', async () => {
const mockOpenSearchServiceSetup = opensearchServiceMock.createSetup();
mockOpenSearchServiceSetup.legacy.client = {
callAsInternalUser: jest.fn(),
asScoped: jest.fn(),
config: {
hosts: ['some host'],
},
};

const opensearchSearch = opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled,
mockOpenSearchServiceSetup
);

await opensearchSearch.search(
(mockDataSourceEnabledContext as unknown) as RequestHandlerContext,
{
dataSourceId,
}
);

expect(mockDataSourceApiCaller).toBeCalled();
expect(mockOpenSearchApiCaller).not.toBeCalled();
});

it('dataSource disabled, send request with dataSourceId get default client', async () => {
it('dataSource enabled, config host exist, send request without dataSourceId should get default client', async () => {
const mockOpenSearchServiceSetup = opensearchServiceMock.createSetup();
mockOpenSearchServiceSetup.legacy.client = {
callAsInternalUser: jest.fn(),
asScoped: jest.fn(),
config: {
hosts: ['some host'],
},
};

const opensearchSearch = opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled,
mockOpenSearchServiceSetup
);

const dataSourceIdToBeTested = [undefined, ''];

dataSourceIdToBeTested.forEach(async (id) => {
const testRequest = id === undefined ? {} : { dataSourceId: id };

await opensearchSearch.search(
(mockDataSourceEnabledContext as unknown) as RequestHandlerContext,
testRequest
);
expect(mockOpenSearchApiCaller).toBeCalled();
expect(mockDataSourceApiCaller).not.toBeCalled();
});
});

it('dataSource enabled, config host is empty / undefined, send request with / without dataSourceId should both throw DataSourceError exception', async () => {
const hostsTobeTested = [undefined, []];
const dataSourceIdToBeTested = [undefined, '', dataSourceId];

hostsTobeTested.forEach((host) => {
const mockOpenSearchServiceSetup = opensearchServiceMock.createSetup();

if (host !== undefined) {
mockOpenSearchServiceSetup.legacy.client = {
callAsInternalUser: jest.fn(),
asScoped: jest.fn(),
config: {
hosts: [],
},
};
}

dataSourceIdToBeTested.forEach(async (id) => {
const testRequest = id === undefined ? {} : { dataSourceId: id };

try {
const opensearchSearch = opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceEnabled,
mockOpenSearchServiceSetup
);

await opensearchSearch.search(
(mockDataSourceEnabledContext as unknown) as RequestHandlerContext,
testRequest
);
} catch (e) {
expect(e).toBeTruthy();
expect(e).toBeInstanceOf(DataSourceError);
expect(e.statusCode).toEqual(400);
}
});
});
});

it('dataSource disabled, send request with dataSourceId should get default client', async () => {
const opensearchSearch = await opensearchSearchStrategyProvider(mockConfig$, mockLogger);

await opensearchSearch.search((mockContext as unknown) as RequestHandlerContext, {
Expand All @@ -154,11 +284,40 @@ describe('OpenSearch search strategy', () => {
expect(mockDataSourceApiCaller).not.toBeCalled();
});

it('dataSource enabled, send request without dataSourceId get default client', async () => {
it('dataSource disabled, send request without dataSourceId should get default client', async () => {
const opensearchSearch = await opensearchSearchStrategyProvider(mockConfig$, mockLogger);

await opensearchSearch.search((mockContext as unknown) as RequestHandlerContext, {});
expect(mockOpenSearchApiCaller).toBeCalled();
expect(mockDataSourceApiCaller).not.toBeCalled();
const dataSourceIdToBeTested = [undefined, ''];

for (const testDataSourceId of dataSourceIdToBeTested) {
await opensearchSearch.search((mockContext as unknown) as RequestHandlerContext, {
dataSourceId: testDataSourceId,
});
expect(mockOpenSearchApiCaller).toBeCalled();
expect(mockDataSourceApiCaller).not.toBeCalled();
}
});

it('dataSource disabled and longNumeralsSupported, send request without dataSourceId should get longNumeralsSupport client', async () => {
const mockOpenSearchServiceSetup = opensearchServiceMock.createSetup();
const opensearchSearch = await opensearchSearchStrategyProvider(
mockConfig$,
mockLogger,
mockSearchUsage,
mockDataSourcePluginSetupWithDataSourceDisabled,
mockOpenSearchServiceSetup,
true
);

const dataSourceIdToBeTested = [undefined, ''];

for (const testDataSourceId of dataSourceIdToBeTested) {
await opensearchSearch.search((mockContext as unknown) as RequestHandlerContext, {
dataSourceId: testDataSourceId,
});
expect(mockOpenSearchApiCallerWithLongNumeralsSupport).toBeCalled();
expect(mockOpenSearchApiCaller).not.toBeCalled();
expect(mockDataSourceApiCaller).not.toBeCalled();
}
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/

import { first } from 'rxjs/operators';
import { SharedGlobalConfig, Logger } from 'opensearch-dashboards/server';
import { SharedGlobalConfig, Logger, OpenSearchServiceSetup } from 'opensearch-dashboards/server';
import { SearchResponse } from 'elasticsearch';
import { Observable } from 'rxjs';
import { ApiResponse } from '@opensearch-project/opensearch';
Expand All @@ -50,6 +50,7 @@ export const opensearchSearchStrategyProvider = (
logger: Logger,
usage?: SearchUsage,
dataSource?: DataSourcePluginSetup,
openSearchServiceSetup?: OpenSearchServiceSetup,
withLongNumeralsSupport?: boolean
): ISearchStrategy => {
return {
Expand All @@ -73,6 +74,13 @@ export const opensearchSearchStrategyProvider = (
});

try {
const isOpenSearchHostsEmpty =
openSearchServiceSetup?.legacy?.client?.config?.hosts?.length === 0;

if (dataSource?.dataSourceEnabled() && isOpenSearchHostsEmpty && !request.dataSourceId) {
throw new Error(`Data source id is required when no openseach hosts config provided`);
}

const client = await decideClient(context, request, withLongNumeralsSupport);
const promise = shimAbortSignal(client.search(params), options?.abortSignal);

Expand All @@ -92,7 +100,7 @@ export const opensearchSearchStrategyProvider = (
} catch (e) {
if (usage) usage.trackError();

if (dataSource && request.dataSourceId) {
if (dataSource?.dataSourceEnabled()) {
throw dataSource.createDataSourceError(e);
}
throw e;
Expand Down
4 changes: 3 additions & 1 deletion src/plugins/data/server/search/search_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
this.initializerContext.config.legacy.globalConfig$,
this.logger,
usage,
dataSource
dataSource,
core.opensearch
)
);

Expand All @@ -141,6 +142,7 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
this.logger,
usage,
dataSource,
core.opensearch,
true
)
);
Expand Down
Loading

0 comments on commit 404ff4d

Please sign in to comment.