Skip to content

Commit

Permalink
Merge branch 'main' into kavilla/support_compression
Browse files Browse the repository at this point in the history
Signed-off-by: Miki <[email protected]>
  • Loading branch information
AMoo-Miki authored Apr 11, 2024
2 parents 1e6846d + 46b17e4 commit 007f616
Show file tree
Hide file tree
Showing 38 changed files with 1,570 additions and 281 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,18 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Multiple Datasource] Enhanced data source selector with default datasource shows as first choice ([#6293](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6293))
- [Multiple Datasource] Add multi data source support to sample vega visualizations ([#6218](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6218))
- [Multiple Datasource] Fetch data source title for DataSourceView when only id is provided ([#6315](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6315)
- [Multiple Datasource] Get data source label when only id is provided in DataSourceSelectable ([#6358](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6358)
- [Workspace] Add permission control logic ([#6052](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6052))
- [Multiple Datasource] Add default icon for selectable component and make sure the default datasource shows automatically ([#6327](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6327))
- [Multiple Datasource] Pass selected data sources to plugin consumers when the multi-select component initially loads ([#6333](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6333))
- [Multiple Datasource] Add installedPlugins list to data source saved object ([#6348](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6348))
- [Multiple Datasource] Add default icon in multi-selectable picker ([#6357](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6357))
- [Workspace] Add APIs to support plugin state in request ([#6303](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6303))
- Support compressing traffic between OpenSearch and OpenSearch Dashboards with `opensearch.compression` ([#6366](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6366))
- [Workspace] Filter left nav menu items according to the current workspace ([#6234](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6234))
- [Multiple Datasource] Refactor data source selector component to include placeholder and add tests ([#6372](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6372))
- [Dynamic Configurations] Improve dynamic configurations by adding cache and simplifying client fetch ([#6364](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6364))
- [MD] Add OpenSearch cluster group label to top of single selectable dropdown ([#6400](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6400))

### 🐛 Bug Fixes

Expand All @@ -106,6 +112,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- [Multiple Datasource] Fix sslConfig for multiple datasource to handle when certificateAuthorities is unset ([#6282](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6282))
- [BUG][Multiple Datasource]Fix bug in data source aggregated view to change it to depend on displayAllCompatibleDataSources property to show the badge value ([#6291](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6291))
- [BUG][Multiple Datasource]Read hideLocalCluster setting from yml and set in data source selector and data source menu ([#6361](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6361))
- [BUG] Fix for checkForFunctionProperty so that order does not matter ([#6248](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6248))

### 🚞 Infrastructure

Expand Down Expand Up @@ -138,6 +145,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

- Remove unused Sass in `tile_map` plugin ([#4110](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4110))
- [Multiple Datasource] Move data source selectable to its own folder, fix test and a few type errors for data source selectable component ([#6287](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/6287))
- Remove KUI usage in `disabled_lab_visualization` ([#5462](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/5462))

### 🔩 Tests

Expand Down
5 changes: 5 additions & 0 deletions src/core/public/doc_links/doc_links_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ export class DocLinksService {
// https://opensearch.org/docs/latest/dashboards/visualize/viz-index/
guide: `${OPENSEARCH_WEBSITE_DOCS}visualize/viz-index/`,
},
management: {
// https://opensearch.org/docs/latest/dashboards/management/advanced-settings/
advancedSettings: `${OPENSEARCH_DASHBOARDS_VERSIONED_DOCS}management/advanced-settings/`,
},
},
noDocumentation: {
auditbeat: `${OPENSEARCH_WEBSITE_DOCS}tools/index/#downloads`,
Expand Down Expand Up @@ -819,6 +823,7 @@ export interface DocLinksStart {
readonly guide: string;
};
readonly visualize: Record<string, string>;
readonly management: Record<string, string>;
};
readonly noDocumentation: {
readonly auditbeat: string;
Expand Down
106 changes: 92 additions & 14 deletions src/plugins/application_config/server/opensearch_config_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.getConfig();

Expand Down Expand Up @@ -77,7 +79,10 @@ describe('OpenSearch Configuration Client', () => {
}),
},
};
const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);

const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.getConfig()).rejects.toThrowError(ERROR_MESSAGE);
});
Expand All @@ -99,11 +104,45 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {
has: jest.fn().mockReturnValue(false),
set: jest.fn(),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.getEntityConfig('config1');

expect(value).toBe('value1');
expect(cache.set).toBeCalledWith('config1', 'value1');
});

it('return configuration value from cache', async () => {
const opensearchClient = {
asInternalUser: {
get: jest.fn().mockImplementation(() => {
return {
body: {
_source: {
value: 'value1',
},
},
};
}),
},
};

const cache = {
has: jest.fn().mockReturnValue(true),
get: jest.fn().mockReturnValue('cachedValue'),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.getEntityConfig('config1');

expect(value).toBe('cachedValue');
expect(cache.get).toBeCalledWith('config1');
});

it('throws error when input is empty', async () => {
Expand All @@ -121,7 +160,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.getEntityConfig(EMPTY_INPUT)).rejects.toThrowError(
ERROR_MESSSAGE_FOR_EMPTY_INPUT
Expand Down Expand Up @@ -151,9 +192,16 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {
has: jest.fn().mockReturnValue(false),
set: jest.fn(),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.getEntityConfig('config1')).rejects.toThrowError(ERROR_MESSAGE);

expect(cache.set).toBeCalledWith('config1', undefined);
});
});

Expand All @@ -167,11 +215,16 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {
del: jest.fn(),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.deleteEntityConfig('config1');

expect(value).toBe('config1');
expect(cache.del).toBeCalledWith('config1');
});

it('throws error when input entity is empty', async () => {
Expand All @@ -183,7 +236,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.deleteEntityConfig(EMPTY_INPUT)).rejects.toThrowError(
ERROR_MESSSAGE_FOR_EMPTY_INPUT
Expand Down Expand Up @@ -213,11 +268,16 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {
del: jest.fn(),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.deleteEntityConfig('config1');

expect(value).toBe('config1');
expect(cache.del).toBeCalledWith('config1');
});

it('return deleted document entity when deletion fails due to document not found', async () => {
Expand All @@ -241,11 +301,16 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {
del: jest.fn(),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.deleteEntityConfig('config1');

expect(value).toBe('config1');
expect(cache.del).toBeCalledWith('config1');
});

it('throws error when opensearch throws error', async () => {
Expand All @@ -271,7 +336,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.deleteEntityConfig('config1')).rejects.toThrowError(ERROR_MESSAGE);
});
Expand All @@ -287,11 +354,16 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {
set: jest.fn(),
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

const value = await client.updateEntityConfig('config1', 'newValue1');

expect(value).toBe('newValue1');
expect(cache.set).toBeCalledWith('config1', 'newValue1');
});

it('throws error when entity is empty ', async () => {
Expand All @@ -303,7 +375,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.updateEntityConfig(EMPTY_INPUT, 'newValue1')).rejects.toThrowError(
ERROR_MESSSAGE_FOR_EMPTY_INPUT
Expand All @@ -319,7 +393,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.updateEntityConfig('config1', EMPTY_INPUT)).rejects.toThrowError(
ERROR_MESSSAGE_FOR_EMPTY_INPUT
Expand Down Expand Up @@ -349,7 +425,9 @@ describe('OpenSearch Configuration Client', () => {
},
};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger);
const cache = {};

const client = new OpenSearchConfigurationClient(opensearchClient, INDEX_NAME, logger, cache);

await expect(client.updateEntityConfig('config1', 'newValue1')).rejects.toThrowError(
ERROR_MESSAGE
Expand Down
25 changes: 22 additions & 3 deletions src/plugins/application_config/server/opensearch_config_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,54 @@
* SPDX-License-Identifier: Apache-2.0
*/

import LRUCache from 'lru-cache';
import { IScopedClusterClient, Logger } from '../../../../src/core/server';

import { ConfigurationClient } from './types';
import { validate } from './string_utils';

export class OpenSearchConfigurationClient implements ConfigurationClient {
private client: IScopedClusterClient;
private configurationIndexName: string;
private readonly logger: Logger;
private cache: LRUCache<string, string | undefined>;

constructor(
scopedClusterClient: IScopedClusterClient,
configurationIndexName: string,
logger: Logger
logger: Logger,
cache: LRUCache<string, string | undefined>
) {
this.client = scopedClusterClient;
this.configurationIndexName = configurationIndexName;
this.logger = logger;
this.cache = cache;
}

async getEntityConfig(entity: string) {
const entityValidated = validate(entity, this.logger);

if (this.cache.has(entityValidated)) {
return this.cache.get(entityValidated);
}

this.logger.info(`Key ${entityValidated} is not found from cache.`);

try {
const data = await this.client.asInternalUser.get({
index: this.configurationIndexName,
id: entityValidated,
});
const value = data?.body?._source?.value;

return data?.body?._source?.value || '';
this.cache.set(entityValidated, value);

return value;
} catch (e) {
const errorMessage = `Failed to get entity ${entityValidated} due to error ${e}`;

this.logger.error(errorMessage);

this.cache.set(entityValidated, undefined);
throw e;
}
}
Expand All @@ -55,6 +68,8 @@ export class OpenSearchConfigurationClient implements ConfigurationClient {
},
});

this.cache.set(entityValidated, newValueValidated);

return newValueValidated;
} catch (e) {
const errorMessage = `Failed to update entity ${entityValidated} with newValue ${newValueValidated} due to error ${e}`;
Expand All @@ -74,15 +89,19 @@ export class OpenSearchConfigurationClient implements ConfigurationClient {
id: entityValidated,
});

this.cache.del(entityValidated);

return entityValidated;
} catch (e) {
if (e?.body?.error?.type === 'index_not_found_exception') {
this.logger.info('Attemp to delete a not found index.');
this.cache.del(entityValidated);
return entityValidated;
}

if (e?.body?.result === 'not_found') {
this.logger.info('Attemp to delete a not found document.');
this.cache.del(entityValidated);
return entityValidated;
}

Expand Down
Loading

0 comments on commit 007f616

Please sign in to comment.