-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Integrate MDS client to ISM #711
Draft
SuZhou-Joe
wants to merge
22
commits into
opensearch-project:2.x
Choose a base branch
from
SuZhou-Joe:feature/mds-client-with-ism
base: 2.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
ddef181
feat: update
SuZhou-Joe 6c8f614
feat: hide dataSourceId
SuZhou-Joe ef9b922
feat: finish optimization
SuZhou-Joe aead0e0
feat: almost finished
SuZhou-Joe de8e65c
feat: update comment
SuZhou-Joe 19537fc
feat: move type to interface.ts
SuZhou-Joe 45ab49c
feat: optimize code
SuZhou-Joe 778d45d
feat: update comment
SuZhou-Joe 9271494
fix: type error
SuZhou-Joe a397455
feat: add data source id
SuZhou-Joe a981584
feat: add context to request
SuZhou-Joe 6a76032
feat: send data_source_id from client
SuZhou-Joe 45e3c40
feat: change data source id
SuZhou-Joe f93a406
feat: add dataSource to json
SuZhou-Joe 205646e
feat: enable global data source selector
SuZhou-Joe e462eba
feat: add mds client enhancement
SuZhou-Joe 8a47047
feat: update comment
SuZhou-Joe 70929ae
feat: move type to interface.ts
SuZhou-Joe 05ce0ce
feat: optimize code
SuZhou-Joe b27eb81
feat: add context to request
SuZhou-Joe 165b91c
feat: add dataSource plugin as required plugins
SuZhou-Joe d1ab5eb
feat: merge
SuZhou-Joe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
public/containers/DataSourceSelector/DataSourceSelector.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
.ism-data-source-selector-section { | ||
padding-left: $ouiSizeS; | ||
position: relative; | ||
padding-right: $ouiSizeS; | ||
&::after { | ||
right: 0; | ||
width: 1px; | ||
bottom: -1 * $ouiSizeS; | ||
height: $ouiSizeXL; | ||
content: ''; | ||
display: inline-block; | ||
position: absolute; | ||
border-right: $ouiBorderThin; | ||
} | ||
.content { | ||
display: flex; | ||
align-items: center; | ||
} | ||
.data-source-label { | ||
margin-right: $ouiSizeS; | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
public/containers/DataSourceSelector/DataSourceSelector.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { EuiComboBox } from "@elastic/eui"; | ||
import React, { useContext, useEffect, useState } from "react"; | ||
import { CoreServicesContext } from "../../components/core_services"; | ||
import "./DataSourceSelector.scss"; | ||
import { getDataSource, setDataSource } from "./utils"; | ||
|
||
interface IDataSourceSelectorProps {} | ||
|
||
export const DataSourceSelector = (props: IDataSourceSelectorProps) => { | ||
const coreStart = useContext(CoreServicesContext); | ||
const [selected] = useState<string>(getDataSource()); | ||
const [options, setOptions] = useState<{ label: string; value: string }[]>([]); | ||
useEffect(() => { | ||
(async () => { | ||
const findResp = await coreStart?.savedObjects.client.find<{ title: string }>({ | ||
type: "data-source", | ||
fields: ["id", "description", "title"], | ||
perPage: 10000, | ||
}); | ||
if (findResp && findResp.savedObjects) { | ||
setOptions( | ||
findResp.savedObjects?.map((item) => ({ | ||
label: item.attributes.title, | ||
value: item.id, | ||
})) | ||
); | ||
} | ||
})(); | ||
}, []); | ||
return ( | ||
<div className="ism-data-source-selector-section"> | ||
<div className="content"> | ||
<EuiComboBox | ||
singleSelection={{ asPlainText: true }} | ||
compressed | ||
fullWidth={false} | ||
placeholder="Select a data source" | ||
prepend="DataSource" | ||
style={{ width: 300 }} | ||
options={options} | ||
selectedOptions={ | ||
selected && options.find((item) => item.value === selected) | ||
? [options.find((item) => item.value === selected) as typeof options[number]] | ||
: [] | ||
} | ||
onChange={async (item) => { | ||
const result = await coreStart?.overlays.openConfirm( | ||
"Switch data source may lead to failure in your current operation and requires a reload on your browser.", | ||
{ | ||
title: "Are you sure to continue?", | ||
confirmButtonText: "Yes, I want to switch data source", | ||
} | ||
); | ||
if (result) { | ||
setDataSource(item?.[0]?.value || ""); | ||
window.location.reload(); | ||
} | ||
}} | ||
></EuiComboBox> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import ReactDOM from "react-dom"; | ||
import React from "react"; | ||
import { DataSourceSelector } from "./DataSourceSelector"; | ||
import { CoreStart } from "opensearch-dashboards/public"; | ||
import { CoreServicesContext } from "../../components/core_services"; | ||
|
||
export const mountDataSourceSelector = (props: { element: HTMLElement; coreStart: CoreStart }) => { | ||
ReactDOM.render( | ||
<CoreServicesContext.Provider value={props.coreStart}> | ||
<DataSourceSelector /> | ||
</CoreServicesContext.Provider>, | ||
props.element | ||
); | ||
return () => { | ||
ReactDOM.unmountComponentAtNode(props.element); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const dataSourceSessionKey = "DATA_SOURCE_IN_ISM"; | ||
export const setDataSource = (dataSourceId: string) => { | ||
sessionStorage.setItem(dataSourceSessionKey, dataSourceId); | ||
}; | ||
|
||
export const getDataSource = (): string => sessionStorage.getItem(dataSourceSessionKey) || ""; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { set } from "lodash"; | ||
import { CoreStart, HttpFetchOptionsWithPath } from "opensearch-dashboards/public"; | ||
|
||
export class MDSIntercept { | ||
private pluginId: string; | ||
private http: CoreStart["http"]; | ||
private getDataSourceId: () => string; | ||
private interceptDestroyHandler: (() => void) | undefined; | ||
constructor(config: { pluginId: string; http: CoreStart["http"]; getDataSourceId: () => string }) { | ||
this.pluginId = config.pluginId; | ||
this.http = config.http; | ||
this.getDataSourceId = config.getDataSourceId; | ||
} | ||
private interceptRequest(fetchOptions: HttpFetchOptionsWithPath) { | ||
set(fetchOptions, `headers._${this.pluginId}_data_source_id_`, this.getDataSourceId()); | ||
return fetchOptions; | ||
} | ||
public start() { | ||
this.interceptDestroyHandler = this.http.intercept({ | ||
request: this.interceptRequest.bind(this), | ||
}); | ||
} | ||
public destroy() { | ||
this.interceptDestroyHandler?.(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { get } from "lodash"; | ||
import { | ||
IContextProvider, | ||
ILegacyScopedClusterClient, | ||
OpenSearchDashboardsRequest, | ||
RequestHandler, | ||
RequestHandlerContext, | ||
} from "opensearch-dashboards/server"; | ||
import { IRequestHandlerContentWithDataSource, IGetClientProps, DashboardRequestEnhancedWithContext } from "./interface"; | ||
|
||
export const getClientSupportMDS = (props: IGetClientProps) => { | ||
const originalAsScoped = props.client.asScoped; | ||
const handler: IContextProvider<RequestHandler<unknown, unknown, unknown>, "core"> = ( | ||
context: RequestHandlerContext, | ||
request: OpenSearchDashboardsRequest | ||
) => { | ||
(request as DashboardRequestEnhancedWithContext)[`${props.pluginId}_context`] = context as IRequestHandlerContentWithDataSource; | ||
return {} as any; | ||
}; | ||
|
||
/** | ||
* asScoped can not get the request context, | ||
* add _context to request | ||
*/ | ||
props.core.http.registerRouteHandlerContext(`${props.pluginId}_MDS_CTX_SUPPORT` as "core", handler); | ||
|
||
/** | ||
* it is not a good practice to rewrite the method like this | ||
* but JS does not provide a method to copy a class instance | ||
*/ | ||
props.client.asScoped = function (request: DashboardRequestEnhancedWithContext): ILegacyScopedClusterClient { | ||
const context = request[`${props.pluginId}_context`]; | ||
|
||
/** | ||
* If the context can not be found | ||
* reject the request and add a log | ||
*/ | ||
if (!context) { | ||
const errorMessage = "There is some error between dashboards and your remote data source, please retry again."; | ||
props.logger.error(errorMessage); | ||
return { | ||
callAsCurrentUser: () => Promise.reject(errorMessage), | ||
callAsInternalUser: () => Promise.reject(errorMessage), | ||
}; | ||
} | ||
|
||
const dataSourceId = props.getDataSourceId?.(context, request); | ||
/** | ||
* If no dataSourceId provided | ||
* use the original client | ||
*/ | ||
if (!dataSourceId) { | ||
props.logger.debug("No dataSourceId, using original client"); | ||
return originalAsScoped.call(props.client, request); | ||
} | ||
|
||
const callApi: ILegacyScopedClusterClient["callAsCurrentUser"] = async (...args) => { | ||
const [endpoint, clientParams, options] = args; | ||
return new Promise(async (resolve, reject) => { | ||
props.logger.debug(`Call api using the data source: ${dataSourceId}`); | ||
try { | ||
const dataSourceClient = await context.dataSource.opensearch.getClient(dataSourceId); | ||
|
||
/** | ||
* extend client if needed | ||
**/ | ||
Object.assign(dataSourceClient, { ...props.onExtendClient?.(dataSourceClient) }); | ||
|
||
/** | ||
* Call the endpoint by providing client | ||
* The logic is much the same as what callAPI does in Dashboards | ||
*/ | ||
const clientPath = endpoint.split("."); | ||
const api: any = get(dataSourceClient, clientPath); | ||
let apiContext = clientPath.length === 1 ? dataSourceClient : get(dataSourceClient, clientPath.slice(0, -1)); | ||
const request = api.call(apiContext, clientParams); | ||
|
||
/** | ||
* In case the request is aborted | ||
*/ | ||
if (options?.signal) { | ||
options.signal.addEventListener("abort", () => { | ||
request.abort(); | ||
reject(new Error("Request was aborted")); | ||
}); | ||
} | ||
const result = await request; | ||
resolve(result.body || result); | ||
} catch (e: any) { | ||
/** | ||
* TODO | ||
* ask dashboard team to add original error to DataSourceError | ||
* so that we can make the client behave exactly the same as legacy client | ||
*/ | ||
reject(e); | ||
} | ||
}); | ||
}; | ||
|
||
/** | ||
* Return a legacy-client-like client | ||
* so that the callers no need to change their code. | ||
*/ | ||
const client: ILegacyScopedClusterClient = { | ||
callAsCurrentUser: callApi, | ||
callAsInternalUser: callApi, | ||
}; | ||
return client; | ||
}; | ||
return props.client; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { OpenSearchDashboardsClient } from "@opensearch-project/opensearch/api/opensearch_dashboards"; | ||
import { | ||
CoreSetup, | ||
ILegacyCustomClusterClient, | ||
LegacyCallAPIOptions, | ||
Logger, | ||
OpenSearchDashboardsRequest, | ||
RequestHandlerContext, | ||
} from "opensearch-dashboards/server"; | ||
|
||
export interface IRequestHandlerContentWithDataSource extends RequestHandlerContext { | ||
dataSource: { | ||
opensearch: { | ||
getClient: (dataSourceId: string) => OpenSearchDashboardsClient; | ||
legacy: { | ||
getClient: ( | ||
dataSourceId: string | ||
) => { | ||
callAPI: (endpoint: string, clientParams?: Record<string, any>, options?: LegacyCallAPIOptions) => Promise<unknown>; | ||
}; | ||
}; | ||
}; | ||
}; | ||
} | ||
|
||
export interface IGetClientProps { | ||
core: CoreSetup; | ||
/** | ||
* We will rewrite the asScoped method of your client | ||
* It would be better that create a new client before you pass in one | ||
*/ | ||
client: ILegacyCustomClusterClient; | ||
onExtendClient?: (client: OpenSearchDashboardsClient) => Record<string, any> | undefined; | ||
getDataSourceId?: (context: RequestHandlerContext, request: OpenSearchDashboardsRequest) => string | undefined; | ||
pluginId: string; | ||
logger: Logger; | ||
} | ||
|
||
export type DashboardRequestEnhancedWithContext = OpenSearchDashboardsRequest & { | ||
[contextKey: string]: IRequestHandlerContentWithDataSource; | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what're the three unknowns?