Skip to content

Commit e737790

Browse files
authored
[Multiple Datasource] Support Amazon OpenSearch Serverless (#3957)
* [Multiple Datasource]Support Amazon OpenSearch Serverless in SigV4 * remove experimental text in yml * Refactor create data source form for authentication Signed-off-by: Su <szhongna@amazon.com>
1 parent c5058a3 commit e737790

File tree

23 files changed

+468
-202
lines changed

23 files changed

+468
-202
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
8585
- Add satisfaction survey link to help menu ([#3676] (https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3676))
8686
- [Vis Builder] Add persistence to visualizations inner state ([#3751](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3751))
8787
- [Table Visualization] Move format table, consolidate types and add unit tests ([#3397](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3397))
88-
88+
- [Multiple Datasource] Support Amazon OpenSearch Serverless ([#3957](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/3957))
8989
### 🐛 Bug Fixes
9090

9191
- [Vis Builder] Fixes auto bounds for timeseries bar chart visualization ([2401](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2401))

config/opensearch_dashboards.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@
229229
# functionality in Visualization.
230230
# vis_builder.enabled: false
231231

232-
# Set the value of this setting to true to enable the experimental multiple data source
233-
# support feature. Use with caution.
232+
# Set the value of this setting to true to enable multiple data source feature.
234233
#data_source.enabled: false
235234
# Set the value of these settings to customize crypto materials to encryption saved credentials
236235
# in data sources.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@
136136
"@hapi/podium": "^4.1.3",
137137
"@hapi/vision": "^6.1.0",
138138
"@hapi/wreck": "^17.1.0",
139-
"@opensearch-project/opensearch": "^2.1.0",
139+
"@opensearch-project/opensearch": "^2.2.0",
140140
"@osd/ace": "1.0.0",
141141
"@osd/analytics": "1.0.0",
142142
"@osd/apm-config-loader": "1.0.0",
@@ -169,7 +169,7 @@
169169
"dns-sync": "^0.2.1",
170170
"elastic-apm-node": "^3.7.0",
171171
"elasticsearch": "^16.7.0",
172-
"http-aws-es": "6.0.0",
172+
"http-aws-es": "npm:@zhongnansu/http-aws-es@6.0.1",
173173
"execa": "^4.0.2",
174174
"expiry-js": "0.1.7",
175175
"fast-deep-equal": "^3.1.1",

packages/osd-opensearch/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"osd:watch": "../../scripts/use_node scripts/build --watch"
1313
},
1414
"dependencies": {
15-
"@opensearch-project/opensearch": "^2.1.0",
15+
"@opensearch-project/opensearch": "^2.2.0",
1616
"@osd/dev-utils": "1.0.0",
1717
"abort-controller": "^3.0.0",
1818
"chalk": "^4.1.0",

src/plugins/data_source/common/data_sources/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export interface SigV4Content extends SavedObjectAttributes {
2525
accessKey: string;
2626
secretKey: string;
2727
region: string;
28+
service?: SigV4ServiceName;
2829
}
2930

3031
export interface UsernamePasswordTypedContent extends SavedObjectAttributes {
@@ -37,3 +38,8 @@ export enum AuthType {
3738
UsernamePasswordType = 'username_password',
3839
SigV4 = 'sigv4',
3940
}
41+
42+
export enum SigV4ServiceName {
43+
OpenSearch = 'es',
44+
OpenSearchServerless = 'aoss',
45+
}

src/plugins/data_source/opensearch_dashboards.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
"server": true,
66
"ui": true,
77
"requiredPlugins": [],
8-
"optionalPlugins": []
8+
"optionalPlugins": [],
9+
"extraPublicDirs": ["common/data_sources"]
910
}

src/plugins/data_source/server/client/configure_client.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,30 @@ describe('configureClient', () => {
167167
expect(decodeAndDecryptSpy).toHaveBeenCalledTimes(2);
168168
});
169169

170+
test('configure client with auth.type == sigv4, service == aoss, should successfully call new Client()', async () => {
171+
savedObjectsMock.get.mockReset().mockResolvedValueOnce({
172+
id: DATA_SOURCE_ID,
173+
type: DATA_SOURCE_SAVED_OBJECT_TYPE,
174+
attributes: {
175+
...dataSourceAttr,
176+
auth: {
177+
type: AuthType.SigV4,
178+
credentials: { ...sigV4AuthContent, service: 'aoss' },
179+
},
180+
},
181+
references: [],
182+
});
183+
184+
jest.spyOn(cryptographyMock, 'decodeAndDecrypt').mockResolvedValue({
185+
decryptedText: 'accessKey',
186+
encryptionContext: { endpoint: 'http://localhost' },
187+
});
188+
189+
await configureClient(dataSourceClientParams, clientPoolSetup, config, logger);
190+
191+
expect(ClientMock).toHaveBeenCalledTimes(1);
192+
});
193+
170194
test('configure test client for non-exist datasource should not call saved object api, nor decode any credential', async () => {
171195
const decodeAndDecryptSpy = jest.spyOn(cryptographyMock, 'decodeAndDecrypt').mockResolvedValue({
172196
decryptedText: 'password',

src/plugins/data_source/server/client/configure_client.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ const getBasicAuthClient = (
160160
};
161161

162162
const getAWSClient = (credential: SigV4Content, clientOptions: ClientOptions): Client => {
163-
const { accessKey, secretKey, region } = credential;
163+
const { accessKey, secretKey, region, service } = credential;
164164

165165
const credentialProvider = (): Promise<Credentials> => {
166166
return new Promise((resolve) => {
@@ -172,6 +172,7 @@ const getAWSClient = (credential: SigV4Content, clientOptions: ClientOptions): C
172172
...AwsSigv4Signer({
173173
region,
174174
getCredentials: credentialProvider,
175+
service,
175176
}),
176177
...clientOptions,
177178
});

src/plugins/data_source/server/client/configure_client_utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export const getAWSCredential = async (
9191
cryptography: CryptographyServiceSetup
9292
): Promise<SigV4Content> => {
9393
const { endpoint } = dataSource;
94-
const { accessKey, secretKey, region } = dataSource.auth.credentials! as SigV4Content;
94+
const { accessKey, secretKey, region, service } = dataSource.auth.credentials! as SigV4Content;
9595

9696
const {
9797
decryptedText: accessKeyText,
@@ -122,6 +122,7 @@ export const getAWSCredential = async (
122122
region,
123123
accessKey: accessKeyText,
124124
secretKey: secretKeyText,
125+
service,
125126
};
126127

127128
return credential;

src/plugins/data_source/server/legacy/configure_legacy_client.test.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { SavedObjectsClientContract } from '../../../../core/server';
77
import { loggingSystemMock, savedObjectsClientMock } from '../../../../core/server/mocks';
88
import { DATA_SOURCE_SAVED_OBJECT_TYPE } from '../../common';
9-
import { AuthType, DataSourceAttributes } from '../../common/data_sources';
9+
import { AuthType, DataSourceAttributes, SigV4Content } from '../../common/data_sources';
1010
import { DataSourcePluginConfigType } from '../../config';
1111
import { cryptographyServiceSetupMock } from '../cryptography_service.mocks';
1212
import { CryptographyServiceSetup } from '../cryptography_service';
@@ -27,6 +27,7 @@ describe('configureLegacyClient', () => {
2727
let clientPoolSetup: OpenSearchClientPoolSetup;
2828
let configOptions: ConfigOptions;
2929
let dataSourceAttr: DataSourceAttributes;
30+
let sigV4AuthContent: SigV4Content;
3031

3132
let mockOpenSearchClientInstance: {
3233
close: jest.Mock;
@@ -71,6 +72,12 @@ describe('configureLegacyClient', () => {
7172
},
7273
} as DataSourceAttributes;
7374

75+
sigV4AuthContent = {
76+
region: 'us-east-1',
77+
accessKey: 'accessKey',
78+
secretKey: 'secretKey',
79+
};
80+
7481
clientPoolSetup = {
7582
getClientFromPool: jest.fn(),
7683
addClientToPool: jest.fn(),
@@ -157,6 +164,42 @@ describe('configureLegacyClient', () => {
157164
expect(mockResult).toBeDefined();
158165
});
159166

167+
test('configure client with auth.type == sigv4 and service param, should call new Client() with service param', async () => {
168+
savedObjectsMock.get.mockReset().mockResolvedValueOnce({
169+
id: DATA_SOURCE_ID,
170+
type: DATA_SOURCE_SAVED_OBJECT_TYPE,
171+
attributes: {
172+
...dataSourceAttr,
173+
auth: {
174+
type: AuthType.SigV4,
175+
credentials: { ...sigV4AuthContent, service: 'aoss' },
176+
},
177+
},
178+
references: [],
179+
});
180+
181+
parseClientOptionsMock.mockReturnValue(configOptions);
182+
183+
jest.spyOn(cryptographyMock, 'decodeAndDecrypt').mockResolvedValue({
184+
decryptedText: 'accessKey',
185+
encryptionContext: { endpoint: 'http://localhost' },
186+
});
187+
188+
await configureLegacyClient(
189+
dataSourceClientParams,
190+
callApiParams,
191+
clientPoolSetup,
192+
config,
193+
logger
194+
);
195+
196+
expect(parseClientOptionsMock).toHaveBeenCalled();
197+
expect(ClientMock).toHaveBeenCalledTimes(1);
198+
expect(ClientMock).toHaveBeenCalledWith(expect.objectContaining({ service: 'aoss' }));
199+
200+
expect(savedObjectsMock.get).toHaveBeenCalledTimes(1);
201+
});
202+
160203
test('configure client with auth.type == username_password and password contaminated', async () => {
161204
const decodeAndDecryptSpy = jest
162205
.spyOn(cryptographyMock, 'decodeAndDecrypt')

0 commit comments

Comments
 (0)