diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index b608b93f2..f2e5d849d 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -3,8 +3,8 @@ "version": "3.0.0.0", "opensearchDashboardsVersion": "3.0.0", "configPath": ["opensearch_index_management"], - "requiredPlugins": ["navigation", "opensearchDashboardsReact", "dataSourceManagement"], - "optionalPlugins": ["managementOverview", "dataSource"], + "requiredPlugins": ["navigation", "opensearchDashboardsReact"], + "optionalPlugins": ["managementOverview", "dataSource", "dataSourceManagement"], "server": true, "ui": true } diff --git a/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx b/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx index e1c58e22f..340fe1120 100644 --- a/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx +++ b/public/components/MDSEnabledComponent/MDSEnabledComponent.tsx @@ -23,7 +23,7 @@ export default class MDSEnabledComponent< // static members cannot reference class type parameters if ( nextProps.multiDataSourceEnabled && - (nextProps.dataSourceId != prevState.dataSourceId || nextProps.dataSourceLabel != prevState.dataSourceLabel) + (nextProps.dataSourceId !== prevState.dataSourceId || nextProps.dataSourceLabel !== prevState.dataSourceLabel) ) { return { dataSourceId: nextProps.dataSourceId, @@ -38,10 +38,13 @@ export function useUpdateUrlWithDataSourceProperties() { const dataSourceMenuProps = useContext(DataSourceMenuContext); const { dataSourceId, dataSourceLabel, multiDataSourceEnabled } = dataSourceMenuProps; const history = useHistory(); + const currentSearch = history.location.search; + const currentQuery = queryString.parse(currentSearch); useEffect(() => { if (multiDataSourceEnabled) { history.replace({ search: queryString.stringify({ + ...currentQuery, dataSourceId, dataSourceLabel, }), diff --git a/public/index_management_app.tsx b/public/index_management_app.tsx index 17429d6c9..8f58e4e92 100644 --- a/public/index_management_app.tsx +++ b/public/index_management_app.tsx @@ -12,12 +12,14 @@ import Main from "./pages/Main"; import { CoreServicesContext } from "./components/core_services"; import "./app.scss"; import { AppPluginStartDependencies } from "./types"; +import { DataSourceManagementPluginSetup } from "../../../src/plugins/data_source_management/public"; export function renderApp( coreStart: CoreStart, pluginStartDependencies: AppPluginStartDependencies, params: AppMountParameters, - landingPage: string + landingPage: string, + dataSourceManagement: DataSourceManagementPluginSetup ) { const isDarkMode = coreStart.uiSettings.get("theme:darkMode") || false; @@ -32,6 +34,7 @@ export function renderApp( landingPage={landingPage} setActionMenu={params.setHeaderActionMenu} multiDataSourceEnabled={!!pluginStartDependencies.dataSource} + dataSourceManagement={dataSourceManagement} /> diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx index f4b671cef..9f89c5c68 100644 --- a/public/pages/Main/Main.tsx +++ b/public/pages/Main/Main.tsx @@ -58,9 +58,9 @@ import ForceMerge from "../ForceMerge"; import Notifications from "../Notifications"; import ComposableTemplates from "../ComposableTemplates"; import CreateComposableTemplate from "../CreateComposableTemplate"; -import { DataSourceMenu } from "../../../../../src/plugins/data_source_management/public"; import { DataSourceMenuContext, DataSourceMenuProperties } from "../../services/DataSourceMenuContext"; import queryString from "query-string"; +import { DataSourceManagementPluginSetup } from "../../../../../src/plugins/data_source_management/public"; enum Navigation { IndexManagement = "Index Management", @@ -128,6 +128,7 @@ interface MainProps extends RouteComponentProps { landingPage: string; setActionMenu: (menuMount: MountPoint | undefined) => void; multiDataSourceEnabled: boolean; + dataSourceManagement: DataSourceManagementPluginSetup; } interface MainState extends Pick {} @@ -310,6 +311,7 @@ export default class Main extends Component { const { landingPage } = this.props; const ROUTE_STYLE = { padding: "25px 25px" }; + const DataSourceMenu = this.props.dataSourceManagement.ui.DataSourceMenu; return ( diff --git a/public/pages/Reindex/container/Reindex/Reindex.tsx b/public/pages/Reindex/container/Reindex/Reindex.tsx index c5944d671..427611b15 100644 --- a/public/pages/Reindex/container/Reindex/Reindex.tsx +++ b/public/pages/Reindex/container/Reindex/Reindex.tsx @@ -713,7 +713,7 @@ class Reindex extends Component { } export default function (props: ReindexProps) { - // in re-index we don't change the data source picker + // in re-index page, user can't change the data source i.e., its in read-only useUpdateUrlWithDataSourceProperties(); return ; } diff --git a/public/pages/SplitIndex/container/SplitIndex/SplitIndex.tsx b/public/pages/SplitIndex/container/SplitIndex/SplitIndex.tsx index 494b1951e..960659f83 100644 --- a/public/pages/SplitIndex/container/SplitIndex/SplitIndex.tsx +++ b/public/pages/SplitIndex/container/SplitIndex/SplitIndex.tsx @@ -270,7 +270,7 @@ export class SplitIndex extends Component { export default function SplitIndexWrapper(props: Omit) { const services = useContext(ServicesContext) as BrowserServices; const coreService = useContext(CoreServicesContext) as CoreStart; - // in split-index we don't change the data source picker + // in split-index page, user can't change the data source i.e., its in read-only useUpdateUrlWithDataSourceProperties(); return ; } diff --git a/public/plugin.ts b/public/plugin.ts index 24746efa7..0c9f92331 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -17,9 +17,11 @@ import { actionRepoSingleton } from "./pages/VisualCreatePolicy/utils/helpers"; import { ROUTES } from "./utils/constants"; import { JobHandlerRegister } from "./JobHandler"; import { ManagementOverViewPluginSetup } from "../../../src/plugins/management_overview/public"; +import { DataSourceManagementPluginSetup } from "../../../src/plugins/data_source_management/public"; interface IndexManagementSetupDeps { managementOverview?: ManagementOverViewPluginSetup; + dataSourceManagement?: DataSourceManagementPluginSetup; } export class IndexManagementPlugin implements Plugin { @@ -27,7 +29,7 @@ export class IndexManagementPlugin implements Plugin { const { renderApp } = await import("./index_management_app"); const [coreStart, depsStart] = await core.getStartServices(); - return renderApp(coreStart, depsStart, params, ROUTES.INDEX_POLICIES); + return renderApp(coreStart, depsStart, params, ROUTES.INDEX_POLICIES, dataSourceManagement); }, }); @@ -70,7 +72,7 @@ export class IndexManagementPlugin implements Plugin { const { renderApp } = await import("./index_management_app"); const [coreStart, depsStart] = await core.getStartServices(); - return renderApp(coreStart, depsStart, params, ROUTES.SNAPSHOT_POLICIES); + return renderApp(coreStart, depsStart, params, ROUTES.SNAPSHOT_POLICIES, dataSourceManagement); }, }); diff --git a/public/services/CommonService.ts b/public/services/CommonService.ts index 75dac4493..333df4ab0 100644 --- a/public/services/CommonService.ts +++ b/public/services/CommonService.ts @@ -3,30 +3,24 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { HttpFetchOptions, HttpSetup } from "opensearch-dashboards/public"; +import { HttpFetchOptions, HttpFetchQuery } from "opensearch-dashboards/public"; import { ServerResponse } from "../../server/models/types"; import { NODE_API } from "../../utils/constants"; import { IAPICaller } from "../../models/interfaces"; +import { MDSEnabledClientService } from "./MDSEnabledClientService"; -export default class CommonService { - httpClient: HttpSetup; - dataSourceId: string; - - constructor(httpClient: HttpSetup, dataSourceId: string = "") { - this.httpClient = httpClient; - this.dataSourceId = dataSourceId; - } - - apiCaller = async (params: IAPICaller): Promise> => { +export default class CommonService extends MDSEnabledClientService { + apiCaller = async (params: IAPICaller, queryObject?: HttpFetchQuery): Promise> => { let url = `${NODE_API.API_CALLER}`; const payload: HttpFetchOptions = {}; + queryObject = this.patchQueryObjectWithDataSourceId(queryObject || {}); payload.method = "POST"; - params.data.dataSourceId = this.dataSourceId; payload.body = JSON.stringify({ data: params.data, endpoint: params.endpoint, hideLog: params.hideLog, }); + payload.query = queryObject; return (await this.httpClient.fetch(url, payload)) as ServerResponse; }; } diff --git a/public/services/IndexService.ts b/public/services/IndexService.ts index 949889f80..e5565f6a4 100644 --- a/public/services/IndexService.ts +++ b/public/services/IndexService.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { HttpFetchQuery, HttpSetup } from "opensearch-dashboards/public"; +import { HttpFetchQuery } from "opensearch-dashboards/public"; import { AcknowledgedResponse, ApplyPolicyResponse, @@ -18,37 +18,24 @@ import { ServerResponse } from "../../server/models/types"; import { NODE_API } from "../../utils/constants"; import { IndexItem } from "../../models/interfaces"; import { SECURITY_EXCEPTION_PREFIX } from "../../server/utils/constants"; +import { MDSEnabledClientService } from "./MDSEnabledClientService"; -export default class IndexService { - httpClient: HttpSetup; - dataSourceId: string; - - constructor(httpClient: HttpSetup, dataSourceId: string = "") { - this.httpClient = httpClient; - this.dataSourceId = dataSourceId; - } - - patchQueryObjectWithObjectId(queryObject: HttpFetchQuery) { - queryObject.dataSourceId = this.dataSourceId; - return queryObject; - } - +export default class IndexService extends MDSEnabledClientService { getIndices = async (queryObject: HttpFetchQuery): Promise> => { let url = `..${NODE_API._INDICES}`; - this.patchQueryObjectWithObjectId(queryObject); - const response = (await this.httpClient.get(url, { query: queryObject })) as ServerResponse; - return response; + queryObject = this.patchQueryObjectWithDataSourceId(queryObject); + return (await this.httpClient.get(url, { query: queryObject })) as ServerResponse; }; getDataStreams = async (queryObject: HttpFetchQuery): Promise> => { const url = `..${NODE_API._DATA_STREAMS}`; - this.patchQueryObjectWithObjectId(queryObject); + queryObject = this.patchQueryObjectWithDataSourceId(queryObject); return await this.httpClient.get(url, { query: queryObject }); }; getAliases = async (queryObject: HttpFetchQuery): Promise> => { const url = `..${NODE_API._ALIASES}`; - this.patchQueryObjectWithObjectId(queryObject); + queryObject = this.patchQueryObjectWithDataSourceId(queryObject); return await this.httpClient.get(url, { query: queryObject }); }; @@ -99,28 +86,30 @@ export default class IndexService { }; }; - applyPolicy = async (indices: string[], policyId: string): Promise> => { + applyPolicy = async (indices: string[], policyId: string, queryObject: HttpFetchQuery): Promise> => { const body = { indices, policyId }; - this.patchQueryObjectWithObjectId(body); + queryObject = this.patchQueryObjectWithDataSourceId(body); const url = `..${NODE_API.APPLY_POLICY}`; - const response = (await this.httpClient.post(url, { body: JSON.stringify(body) })) as ServerResponse; - return response; + return (await this.httpClient.post(url, { + body: JSON.stringify(body), + query: queryObject, + })) as ServerResponse; }; - editRolloverAlias = async (index: string, alias: string): Promise> => { + editRolloverAlias = async (index: string, alias: string, queryObject: HttpFetchQuery): Promise> => { const body = { index, alias }; - this.patchQueryObjectWithObjectId(body); + queryObject = this.patchQueryObjectWithDataSourceId(body); const url = `..${NODE_API.EDIT_ROLLOVER_ALIAS}`; - const response = (await this.httpClient.post(url, { body: JSON.stringify(body) })) as ServerResponse; - return response; + return (await this.httpClient.post(url, { + body: JSON.stringify(body), + query: queryObject, + })) as ServerResponse; }; searchPolicies = async (searchValue: string, source: boolean = false): Promise> => { const str = searchValue.trim(); - const queryObject = { from: 0, size: 10, search: str, sortDirection: "desc", sortField: "id" }; - this.patchQueryObjectWithObjectId(queryObject); + const queryObject = this.patchQueryObjectWithDataSourceId({ from: 0, size: 10, search: str, sortDirection: "desc", sortField: "id" }); const url = `..${NODE_API.POLICIES}`; - const response = (await this.httpClient.get(url, { query: queryObject })) as ServerResponse; - return response; + return (await this.httpClient.get(url, { query: queryObject })) as ServerResponse; }; } diff --git a/public/services/MDSEnabledClientService.ts b/public/services/MDSEnabledClientService.ts new file mode 100644 index 000000000..2b7c012d9 --- /dev/null +++ b/public/services/MDSEnabledClientService.ts @@ -0,0 +1,17 @@ +import { HttpFetchQuery, HttpSetup } from "opensearch-dashboards/public"; + +export abstract class MDSEnabledClientService { + httpClient: HttpSetup; + dataSourceId: string; + + constructor(httpClient: HttpSetup, dataSourceId: string = "") { + this.httpClient = httpClient; + this.dataSourceId = dataSourceId; + } + + patchQueryObjectWithDataSourceId(queryObject: HttpFetchQuery) { + queryObject = queryObject || {}; + queryObject.dataSourceId = this.dataSourceId; + return queryObject; + } +} diff --git a/server/plugin.ts b/server/plugin.ts index 8d60434de..f925e3be3 100644 --- a/server/plugin.ts +++ b/server/plugin.ts @@ -70,7 +70,9 @@ export class IndexPatternManagementPlugin implements Plugin; dataSourceId?: Type } = { search: schema.maybe(schema.string()), }; if (dataSourceEnabled) { diff --git a/server/routes/indices.ts b/server/routes/indices.ts index 94fdf7a38..b5cdc0eb4 100644 --- a/server/routes/indices.ts +++ b/server/routes/indices.ts @@ -7,6 +7,7 @@ import { schema } from "@osd/config-schema"; import { NodeServices } from "../models/interfaces"; import { NODE_API } from "../../utils/constants"; import { IRouter } from "../../../../src/core/server"; +import { ObjectType, AnyType } from "@osd/config-schema/target/out"; export default function (services: NodeServices, router: IRouter, dataSourceEnabled: boolean = false) { const { indexService } = services; @@ -40,12 +41,21 @@ export default function (services: NodeServices, router: IRouter, dataSourceEnab indexService.getIndices ); + let genericBodyAndDataSourceIdQuery: { body: AnyType; query?: ObjectType } = { + body: schema.any(), + }; + if (dataSourceEnabled) { + genericBodyAndDataSourceIdQuery = { + ...genericBodyAndDataSourceIdQuery, + query: schema.object({ + dataSourceId: schema.string(), + }), + }; + } router.post( { path: NODE_API.APPLY_POLICY, - validate: { - body: schema.any(), - }, + validate: genericBodyAndDataSourceIdQuery, }, indexService.applyPolicy ); @@ -53,9 +63,7 @@ export default function (services: NodeServices, router: IRouter, dataSourceEnab router.post( { path: NODE_API.EDIT_ROLLOVER_ALIAS, - validate: { - body: schema.any(), - }, + validate: genericBodyAndDataSourceIdQuery, }, indexService.editRolloverAlias ); diff --git a/server/services/AliasServices.ts b/server/services/AliasServices.ts index 7dadcac1e..39592b5af 100644 --- a/server/services/AliasServices.ts +++ b/server/services/AliasServices.ts @@ -12,9 +12,9 @@ import { import { ServerResponse } from "../models/types"; import { Alias, GetAliasesResponse } from "../models/interfaces"; import { SECURITY_EXCEPTION_PREFIX } from "../utils/constants"; -import { OpenSearchISMService } from "./OpenSearchISMService"; +import { MDSEnabledClientService } from "./MDSEnabledClientService"; -export default class AliasServices extends OpenSearchISMService { +export default class AliasServices extends MDSEnabledClientService { getAliases = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, @@ -25,10 +25,7 @@ export default class AliasServices extends OpenSearchISMService { search?: string; }; - const useQuery = !request.body; - const usedParam = useQuery ? request.query : request.body; - const { dataSourceId = "" } = usedParam || {}; - const callWithRequest = this.getClientBasedOnDataSource(context, request, dataSourceId); + const callWithRequest = this.getClientBasedOnDataSource(context, request); const [aliases, apiAccessible, errMsg] = await getAliases(callWithRequest, search); if (!apiAccessible) diff --git a/server/services/CommonService.ts b/server/services/CommonService.ts index 5f89aceea..6d0c2674c 100644 --- a/server/services/CommonService.ts +++ b/server/services/CommonService.ts @@ -12,11 +12,11 @@ import { RequestHandlerContext, } from "../../../../src/core/server"; import { IAPICaller } from "../../models/interfaces"; -import { OpenSearchISMService } from "./OpenSearchISMService"; +import { MDSEnabledClientService } from "./MDSEnabledClientService"; const VALID_METHODS = ["HEAD", "GET", "POST", "PUT", "DELETE"]; -export default class CommonService extends OpenSearchISMService { +export default class CommonService extends MDSEnabledClientService { apiCaller = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, @@ -28,9 +28,7 @@ export default class CommonService extends OpenSearchISMService { try { const finalData = data; - const { dataSourceId = "" } = data; - const callWithRequest = this.getClientBasedOnDataSource(context, request, dataSourceId); - delete finalData.dataSourceId; + const callWithRequest = this.getClientBasedOnDataSource(context, request); /** * The endpoint must not be an empty string, reference from proxy caller diff --git a/server/services/DataStreamService.ts b/server/services/DataStreamService.ts index 18ca4eed1..26f6296ef 100644 --- a/server/services/DataStreamService.ts +++ b/server/services/DataStreamService.ts @@ -13,9 +13,9 @@ import { import { ServerResponse } from "../models/types"; import { DataStream, GetDataStreamsResponse, IndexToDataStream } from "../models/interfaces"; import { SECURITY_EXCEPTION_PREFIX } from "../utils/constants"; -import { OpenSearchISMService } from "./OpenSearchISMService"; +import { MDSEnabledClientService } from "./MDSEnabledClientService"; -export default class DataStreamService extends OpenSearchISMService { +export default class DataStreamService extends MDSEnabledClientService { getDataStreams = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, @@ -26,10 +26,7 @@ export default class DataStreamService extends OpenSearchISMService { search?: string; }; - const useQuery = !request.body; - const usedParam = useQuery ? request.query : request.body; - const { dataSourceId = "" } = usedParam || {}; - const callWithRequest = this.getClientBasedOnDataSource(context, request, dataSourceId); + const callWithRequest = this.getClientBasedOnDataSource(context, request); const [dataStreams, apiAccessible, errMsg] = await getDataStreams(callWithRequest, search); if (!apiAccessible) diff --git a/server/services/IndexService.ts b/server/services/IndexService.ts index 1d540e250..767a3374f 100644 --- a/server/services/IndexService.ts +++ b/server/services/IndexService.ts @@ -25,9 +25,9 @@ import { import { getSearchString } from "../utils/helpers"; import { getIndexToDataStreamMapping } from "./DataStreamService"; import { IRecoveryItem, IReindexItem, ITaskItem } from "../../models/interfaces"; -import { OpenSearchISMService } from "./OpenSearchISMService"; +import { MDSEnabledClientService } from "./MDSEnabledClientService"; -export default class IndexService extends OpenSearchISMService { +export default class IndexService extends MDSEnabledClientService { getIndices = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, @@ -46,7 +46,6 @@ export default class IndexService extends OpenSearchISMService { showDataStreams, expandWildcards, exactSearch, - dataSourceId = "", } = request.query as { from: string; size: string; @@ -59,7 +58,6 @@ export default class IndexService extends OpenSearchISMService { showDataStreams: boolean; expandWildcards?: string; exactSearch?: string; - dataSourceId?: string; }; const params: { index: string; @@ -83,7 +81,7 @@ export default class IndexService extends OpenSearchISMService { params.index = exactSearch; } - const callWithRequest = this.getClientBasedOnDataSource(context, request, dataSourceId); + const callWithRequest = this.getClientBasedOnDataSource(context, request); const [recoverys, tasks, indicesResponse, indexToDataStreamMapping]: [ IRecoveryItem[], diff --git a/server/services/OpenSearchISMService.ts b/server/services/MDSEnabledClientService.ts similarity index 84% rename from server/services/OpenSearchISMService.ts rename to server/services/MDSEnabledClientService.ts index 313d00d55..8ddfe5fe0 100644 --- a/server/services/OpenSearchISMService.ts +++ b/server/services/MDSEnabledClientService.ts @@ -5,7 +5,7 @@ import { RequestHandlerContext, } from "opensearch-dashboards/server"; -export abstract class OpenSearchISMService { +export abstract class MDSEnabledClientService { osDriver: ILegacyCustomClusterClient; dataSourceEnabled: boolean; @@ -13,11 +13,12 @@ export abstract class OpenSearchISMService { this.osDriver = osDriver; this.dataSourceEnabled = dataSourceEnabled; } + getClientBasedOnDataSource( context: RequestHandlerContext, - request: OpenSearchDashboardsRequest, - dataSourceId: string + request: OpenSearchDashboardsRequest ): (endpoint: string, clientParams: Record, options?: LegacyCallAPIOptions | undefined) => Promise { + const { dataSourceId = "" } = request.query as { dataSourceId?: string }; if (this.dataSourceEnabled && dataSourceId && dataSourceId.trim().length != 0) { // non-zero data source id return context.dataSource.opensearch.legacy.getClient(dataSourceId).callAPI;