Skip to content

Commit

Permalink
[Multiple Datasource][Version Decoupling] Add data source engine type…
Browse files Browse the repository at this point in the history
… to data source saved object (opensearch-project#7026)

* [Multiple Datasource][Version Decoupling] Add data source engine type to data source saved object

Signed-off-by: Zilong Xia <[email protected]>

* Changeset file for PR opensearch-project#7026 created/updated

---------

Signed-off-by: Zilong Xia <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
ZilongX and opensearch-changeset-bot[bot] authored Jun 14, 2024
1 parent a4aa682 commit 190dab0
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 21 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/7026.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
fix:
- [MDS] Add data source engine type to data source saved object ([#7026](https:/opensearch-project/OpenSearch-Dashboards/pull/7026))
8 changes: 8 additions & 0 deletions src/plugins/data_source/common/data_sources/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface DataSourceAttributes extends SavedObjectAttributes {
description?: string;
endpoint: string;
dataSourceVersion?: string;
dataSourceEngineType?: DataSourceEngineType;
installedPlugins?: string[];
auth: {
type: AuthType | string;
Expand Down Expand Up @@ -52,3 +53,10 @@ export enum SigV4ServiceName {
}

export { DataSourceError } from './error';

export enum DataSourceEngineType {
OpenSearch = 'OpenSearch',
OpenSearchServerless = 'OpenSearch Serverless',
Elasticsearch = 'Elasticsearch',
NA = 'No Engine Type Available',
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,23 @@ describe('DataSourceManagement: data_source_connection_validator.ts', () => {
expect(validateDataSourcesResponse.statusCode).toBe(200);
});

test('fetchDataSourceVersion - Success: opensearch client response code is 200 and response body have version number', async () => {
test('fetchDataSourceInfo - Success: opensearch client response code is 200 and response body have version number and distribution', async () => {
const opensearchClient = opensearchServiceMock.createOpenSearchClient();
opensearchClient.info.mockResolvedValue(
opensearchServiceMock.createApiResponse({
statusCode: 200,
body: {
version: {
number: '2.11.0',
distribution: 'opensearch',
},
},
})
);
const dataSourceValidator = new DataSourceConnectionValidator(opensearchClient, {});
const fetchDataSourcesVersionResponse = await dataSourceValidator.fetchDataSourceVersion();
expect(fetchDataSourcesVersionResponse).toBe('2.11.0');
const fetchDataSourcesVersionResponse = await dataSourceValidator.fetchDataSourceInfo();
expect(fetchDataSourcesVersionResponse.dataSourceVersion).toBe('2.11.0');
expect(fetchDataSourcesVersionResponse.dataSourceEngineType).toBe('OpenSearch');
});

test('fetchInstalledPlugins - Success: opensearch client response code is 200 and response body have installed plugin list', async () => {
Expand Down Expand Up @@ -92,8 +94,8 @@ describe('DataSourceManagement: data_source_connection_validator.ts', () => {
}
});

// In case fetchDataSourceVersion call succeeded yet did not return version number, return an empty version instead of raising exceptions
test('fetchDataSourceVersion - Success:opensearch client response code is 200 but response body does not have version number', async () => {
// In case fetchDataSourceInfo call succeeded yet did not return version number and distribution, return an empty info instead of raising exceptions
test('fetchDataSourceInfo - Success:opensearch client response code is 200 but response body does not have version number', async () => {
const opensearchClient = opensearchServiceMock.createOpenSearchClient();
opensearchClient.info.mockResolvedValue(
opensearchServiceMock.createApiResponse({
Expand All @@ -104,8 +106,9 @@ describe('DataSourceManagement: data_source_connection_validator.ts', () => {
})
);
const dataSourceValidator = new DataSourceConnectionValidator(opensearchClient, {});
const fetchDataSourcesVersionResponse = await dataSourceValidator.fetchDataSourceVersion();
expect(fetchDataSourcesVersionResponse).toBe('');
const fetchDataSourcesVersionResponse = await dataSourceValidator.fetchDataSourceInfo();
expect(fetchDataSourcesVersionResponse.dataSourceVersion).toBe('');
expect(fetchDataSourcesVersionResponse.dataSourceEngineType).toBe('No Engine Type Available');
});

test('failure: opensearch client response code is other than 200', async () => {
Expand All @@ -130,8 +133,8 @@ describe('DataSourceManagement: data_source_connection_validator.ts', () => {
});
});

// In case fetchDataSourceVersion call failed, return an empty version instead of raising exceptions
test('fetchDataSourceVersion - Failure: opensearch client response code is other than 200', async () => {
// In case fetchDataSourceInfo call failed, return an empty info instead of raising exceptions
test('fetchDataSourceInfo - Failure: opensearch client response code is other than 200', async () => {
const statusCodeList = [100, 202, 300, 400, 500];
statusCodeList.forEach(async function (code) {
const opensearchClient = opensearchServiceMock.createOpenSearchClient();
Expand All @@ -144,8 +147,11 @@ describe('DataSourceManagement: data_source_connection_validator.ts', () => {
})
);
const dataSourceValidator = new DataSourceConnectionValidator(opensearchClient, {});
const fetchDataSourcesVersionResponse = await dataSourceValidator.fetchDataSourceVersion();
expect(fetchDataSourcesVersionResponse).toBe('');
const fetchDataSourcesVersionResponse = await dataSourceValidator.fetchDataSourceInfo();
expect(fetchDataSourcesVersionResponse.dataSourceVersion).toBe('');
expect(fetchDataSourcesVersionResponse.dataSourceEngineType).toBe(
'No Engine Type Available'
);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import { OpenSearchClient } from 'opensearch-dashboards/server';
import { createDataSourceError } from '../lib/error';
import { SigV4ServiceName } from '../../common/data_sources';
import { DataSourceEngineType, SigV4ServiceName } from '../../common/data_sources';
import { DataSourceInfo } from '../types';

export class DataSourceConnectionValidator {
constructor(
private readonly callDataCluster: OpenSearchClient,
Expand Down Expand Up @@ -36,26 +38,42 @@ export class DataSourceConnectionValidator {
}
}

async fetchDataSourceVersion() {
let dataSourceVersion = '';
async fetchDataSourceInfo() {
const dataSourceInfo: DataSourceInfo = {
dataSourceVersion: '',
dataSourceEngineType: DataSourceEngineType.NA,
};

try {
// OpenSearch Serverless does not have version concept
if (
this.dataSourceAttr.auth?.credentials?.service === SigV4ServiceName.OpenSearchServerless
) {
return dataSourceVersion;
dataSourceInfo.dataSourceEngineType = DataSourceEngineType.OpenSearchServerless;
return dataSourceInfo;
}

await this.callDataCluster
.info()
.then((response) => response.body)
.then((body) => {
dataSourceVersion = body.version.number;
dataSourceInfo.dataSourceVersion = body.version.number;

if (
body.version.distribution !== null &&
body.version.distribution !== undefined &&
body.version.distribution === 'opensearch'
) {
dataSourceInfo.dataSourceEngineType = DataSourceEngineType.OpenSearch;
} else {
dataSourceInfo.dataSourceEngineType = DataSourceEngineType.Elasticsearch;
}
});

return dataSourceVersion;
return dataSourceInfo;
} catch (e) {
// return empty dataSource version instead of throwing exception in case info() api call fails
return dataSourceVersion;
// return default dataSourceInfo instead of throwing exception in case info() api call fails
return dataSourceInfo;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {

const router = httpSetup.createRouter('');
dataSourceClient.info.mockImplementationOnce(() =>
opensearchClientMock.createSuccessTransportRequestPromise({ version: { number: '2.11.0' } })
opensearchClientMock.createSuccessTransportRequestPromise({
version: { number: '2.11.0', distribution: 'opensearch' },
})
);

const installedPlugins = [
Expand Down Expand Up @@ -201,6 +203,7 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {
.expect(200);
expect(result.body).toEqual({
dataSourceVersion: '2.11.0',
dataSourceEngineType: 'OpenSearch',
installedPlugins: ['opensearch-ml', 'opensearch-sql'],
});
expect(dataSourceServiceSetupMock.getDataSourceClient).toHaveBeenCalledWith(
Expand All @@ -224,6 +227,7 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {
.expect(200);
expect(result.body).toEqual({
dataSourceVersion: '2.11.0',
dataSourceEngineType: 'OpenSearch',
installedPlugins: ['opensearch-ml', 'opensearch-sql'],
});
});
Expand Down Expand Up @@ -324,6 +328,7 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {
.expect(200);
expect(result.body).toEqual({
dataSourceVersion: '2.11.0',
dataSourceEngineType: 'OpenSearch',
installedPlugins: ['opensearch-ml', 'opensearch-sql'],
});
});
Expand All @@ -338,6 +343,7 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {
.expect(200);
expect(result.body).toEqual({
dataSourceVersion: '2.11.0',
dataSourceEngineType: 'OpenSearch',
installedPlugins: ['opensearch-ml', 'opensearch-sql'],
});
});
Expand All @@ -352,6 +358,7 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {
.expect(200);
expect(result.body).toEqual({
dataSourceVersion: '2.11.0',
dataSourceEngineType: 'OpenSearch',
installedPlugins: ['opensearch-ml', 'opensearch-sql'],
});
});
Expand All @@ -366,6 +373,7 @@ describe(`Fetch DataSource MetaData ${URL}`, () => {
.expect(200);
expect(result.body).toEqual({
dataSourceVersion: '2.11.0',
dataSourceEngineType: 'OpenSearch',
installedPlugins: ['opensearch-ml', 'opensearch-sql'],
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,15 @@ export const registerFetchDataSourceMetaDataRoute = async (
dataSourceAttr
);

const dataSourceVersion = await dataSourceValidator.fetchDataSourceVersion();
const dataSourceInfo = await dataSourceValidator.fetchDataSourceInfo();
const dataSourceVersion = dataSourceInfo.dataSourceVersion;
const dataSourceEngineType = dataSourceInfo.dataSourceEngineType;
const installedPlugins = Array.from(await dataSourceValidator.fetchInstalledPlugins());

return response.ok({
body: {
dataSourceVersion,
dataSourceEngineType,
installedPlugins,
},
});
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/data_source/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from 'src/core/server';
import {
DataSourceAttributes,
DataSourceEngineType,
AuthType,
UsernamePasswordTypedContent,
SigV4Content,
Expand Down Expand Up @@ -98,3 +99,8 @@ export interface DataSourcePluginStart {
getAuthenticationMethodRegistry: () => IAuthenticationMethodRegistry;
getCustomApiSchemaRegistry: () => CustomApiSchemaRegistry;
}

export interface DataSourceInfo {
dataSourceVersion?: string;
dataSourceEngineType?: DataSourceEngineType;
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const CreateDataSourceWizard: React.FunctionComponent<CreateDataSourceWiz
// Fetch data source metadata from added OS/ES domain/cluster
const metadata = await fetchDataSourceMetaData(http, attributes);
attributes.dataSourceVersion = metadata.dataSourceVersion;
attributes.dataSourceEngineType = metadata.dataSourceEngineType;
attributes.installedPlugins = metadata.installedPlugins;
await createSingleDataSource(savedObjects.client, attributes);
// Set the first create data source as default data source.
Expand Down

0 comments on commit 190dab0

Please sign in to comment.