diff --git a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap index adf1595cf9..a4c2f2572b 100644 --- a/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap +++ b/public/components/data_connections/components/__tests__/__snapshots__/data_connection.test.tsx.snap @@ -62,7 +62,7 @@ exports[`Data Connection Page test Renders data connection page with data 1`] =
- Access control + Authentication method
- Connection description + Data source description
- my_spark3 + - +
+ +
+
+ Query permissions +
+
+ Everyone
+ + +
+
- Connection status + Spark data location
- j-3UNQLT1MPBGLG + -
@@ -268,20 +290,6 @@ exports[`Data Connection Page test Renders data connection page with data 1`] = aria-controls="random_html_id" aria-selected="true" class="euiTab euiTab-isSelected" - id="data" - role="tab" - type="button" - > - - Data - - -
+ > +
+
+
+ + + Configurations may be managed elsewhere. + +
+
+
+ Access to data can be managed in other systems outside of OpenSearch. Check with your administrator for additional configurations. +
+
+
+
+
+
+
+
+

+ Access Control +

+ Control which OpenSearch users have access to this data source. +
+
+
+ +
+
+
+
+
+
+
+
+ Query access +
+
+ - +
+
+
+
+
+
+
+
+
- - - Connection Status - - - - @@ -295,23 +278,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- @@ -371,23 +337,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- @@ -447,23 +396,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- @@ -523,23 +455,6 @@ exports[`Manage Data Connections Table test Renders manage data connections tabl
- -
- Connection Status -
-
-
-
- diff --git a/public/components/data_connections/components/__tests__/data_connection.test.tsx b/public/components/data_connections/components/__tests__/data_connection.test.tsx index 3146b747f9..9957198101 100644 --- a/public/components/data_connections/components/__tests__/data_connection.test.tsx +++ b/public/components/data_connections/components/__tests__/data_connection.test.tsx @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { configure, mount } from 'enzyme'; +import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; -import { act, waitFor } from '@testing-library/react'; +import { act } from '@testing-library/react'; import React from 'react'; -import { describeDataConnection } from './testing_constants'; +import { describeDataConnection, mockRoleData } from '../../../../../test/datasources'; import { DataConnection } from '../data_connection'; import ReactDOM from 'react-dom'; @@ -17,7 +17,7 @@ jest.mock('../../../../../public/framework/core_refs', () => ({ setBreadcrumbs: jest.fn(), }, http: { - get: jest.fn().mockResolvedValue(describeDataConnection), + get: jest.fn().mockResolvedValueOnce(mockRoleData).mockResolvedValue(describeDataConnection), }, }, })); @@ -29,7 +29,6 @@ describe('Data Connection Page test', () => { const pplService = { fetch: jest.fn(), }; - const wrapper = mount(); const container = document.createElement('div'); await act(() => { ReactDOM.render(, container); diff --git a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx index fe7369426a..cd5509f1b8 100644 --- a/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx +++ b/public/components/data_connections/components/__tests__/manage_data_connections_table.test.tsx @@ -8,20 +8,8 @@ import Adapter from 'enzyme-adapter-react-16'; import { act } from '@testing-library/react'; import React from 'react'; import { ManageDataConnectionsTable } from '../manage_data_connections_table'; -import { showDataConnectionsData } from './testing_constants'; +import { showDataConnectionsData } from '../../../../../test/datasources'; import ReactDOM from 'react-dom'; -import { coreRefs } from '../../../../../public/framework/core_refs'; - -jest.mock('../../../../../public/framework/core_refs', () => ({ - coreRefs: { - chrome: { - setBreadcrumbs: jest.fn(), - }, - http: { - get: jest.fn().mockResolvedValue(showDataConnectionsData), - }, - }, -})); describe('Manage Data Connections Table test', () => { configure({ adapter: new Adapter() }); diff --git a/public/components/data_connections/components/__tests__/testing_constants.ts b/public/components/data_connections/components/__tests__/testing_constants.ts deleted file mode 100644 index 65258fb27b..0000000000 --- a/public/components/data_connections/components/__tests__/testing_constants.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -export const showDataConnectionsData = { - schema: [ - { - name: 'DATASOURCE_NAME', - type: 'string', - }, - { - name: 'CONNECTOR_TYPE', - type: 'string', - }, - ], - datarows: [ - ['my_spark_actual', 'SPARK'], - ['@opensearch', 'OPENSEARCH'], - ['my_spark', 'SPARK'], - ], - total: 3, - size: 3, - jsonData: [ - { - DATASOURCE_NAME: 'my_spark3', - CONNECTOR_TYPE: 'SPARK', - }, - { - DATASOURCE_NAME: 'my_spark4', - CONNECTOR_TYPE: 'SPARK', - }, - { - DATASOURCE_NAME: 'my_spark', - CONNECTOR_TYPE: 'SPARK', - }, - { - DATASOURCE_NAME: 'my_spark2', - CONNECTOR_TYPE: 'SPARK', - }, - ], -}; - -export const describeDataConnection = { - name: 'my_spark3', - connector: 'SPARK', - allowedRoles: [], - properties: { - 'spark.connector': 'emr', - 'spark.datasource.flint.host': '0.0.0.0', - 'spark.datasource.flint.integration': - 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', - 'spark.datasource.flint.port': '9200', - 'spark.datasource.flint.scheme': 'http', - 'emr.cluster': 'j-3UNQLT1MPBGLG', - }, -}; diff --git a/public/components/data_connections/components/access_control_tab.tsx b/public/components/data_connections/components/access_control_tab.tsx index 15c8491b90..58fdffde33 100644 --- a/public/components/data_connections/components/access_control_tab.tsx +++ b/public/components/data_connections/components/access_control_tab.tsx @@ -10,16 +10,14 @@ import { EuiSpacer, EuiText, EuiHorizontalRule, - EuiBottomBar, - EuiButtonEmpty, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; import { EuiPanel } from '@elastic/eui'; -import { QUERY_ALL, QUERY_RESTRICT } from '../../../../common/constants/data_connections'; -import { AccessControlCallout } from './access_control_callout'; +import { ConnectionManagementCallout } from './connection_management_callout'; import { coreRefs } from '../../../../public/framework/core_refs'; import { QueryPermissionsConfiguration } from './query_permissions'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; +import { SaveOrCancel } from './save_or_cancel'; interface AccessControlTabProps { dataConnection: string; @@ -109,36 +107,10 @@ export const AccessControlTab = (props: AccessControlTabProps) => { ); }; - const SaveOrCancel = () => { - return ( - - - - { - setMode('view'); - }} - color="ghost" - size="s" - iconType="cross" - > - Discard change(s) - - - - - Save - - - - - ); - }; - return ( <> - + @@ -146,7 +118,14 @@ export const AccessControlTab = (props: AccessControlTabProps) => { {mode === 'view' ? : } - {mode === 'edit' && } + {mode === 'edit' && ( + { + setMode('view'); + }} + onSave={saveChanges} + /> + )} ); diff --git a/public/components/data_connections/components/connection_configuration.tsx b/public/components/data_connections/components/connection_configuration.tsx new file mode 100644 index 0000000000..8ce2bd7bed --- /dev/null +++ b/public/components/data_connections/components/connection_configuration.tsx @@ -0,0 +1,139 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiFieldPassword, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSelect, + EuiSpacer, + EuiText, + EuiTextArea, +} from '@elastic/eui'; +import { EuiSelectOption } from '@elastic/eui/src/components/form/select'; +import React, { useState } from 'react'; + +interface ConnectionConfigurationProps { + connectionName: string; + connectionDetails: string; + onConnectionDetailsChange: (e: any) => void; + authenticationOptions: EuiSelectOption[]; + setSelectedAuthenticationMethod: (authenticationMethod: EuiSelectOption) => void; + selectedAuthenticationMethod: string; +} + +export const ConnectionConfiguration = (props: ConnectionConfigurationProps) => { + const { + connectionName, + connectionDetails, + onConnectionDetailsChange, + authenticationOptions, + selectedAuthenticationMethod, + setSelectedAuthenticationMethod, + } = props; + const [details, setDetails] = useState(connectionDetails); + + const [password, setPassword] = useState(''); + const [dual, setDual] = useState(true); + + const NameRow = () => { + return ( + + + Data source name + + This is the name of the data source and how it will be referenced in OpenSearch + Dashboards. + + + + + + + + + ); + }; + + const SparkEndpointRow = () => { + return ( + + + Spark endpoint URL + + { + "The URL for your Spark cluster and where your data is. This is what OpenSearch will connect to. The endpoint URL can't be changed. If you'd like to use another endpoint create a new data source." + } + + + + + + + + + ); + }; + + return ( + + + + + + Description - optional + + Text that can help identify the data source or share additional details + + + + + { + setDetails(e.target.value); + }} + onBlur={onConnectionDetailsChange} + /> + + + + + + + + + Authentication details + + This is information used to authenticate and create a data source with Spark. + + + + + setSelectedAuthenticationMethod(e)} + /> + + + + + + setPassword(e.target.value)} + /> + + + + + ); +}; diff --git a/public/components/data_connections/components/connection_details.tsx b/public/components/data_connections/components/connection_details.tsx new file mode 100644 index 0000000000..44cd206f43 --- /dev/null +++ b/public/components/data_connections/components/connection_details.tsx @@ -0,0 +1,159 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiText, + EuiHorizontalRule, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { ConnectionManagementCallout } from './connection_management_callout'; +import { coreRefs } from '../../../../public/framework/core_refs'; +import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; +import { SaveOrCancel } from './save_or_cancel'; +import { ConnectionConfiguration } from './connection_configuration'; + +interface ConnectionDetailProps { + dataConnection: string; + connector: string; + allowedRoles: string[]; + properties: unknown; +} + +export const ConnectionDetails = (props: ConnectionDetailProps) => { + const [mode, setMode] = useState<'view' | 'edit'>('view'); + const { http } = coreRefs; + + const { dataConnection, connector, allowedRoles, properties } = props; + const [connectionDetails, setConnectionDetails] = useState(''); + const onChange = (e) => { + setConnectionDetails(e.target.value); + }; + const authenticationOptions = [{ value: 'option_one', text: 'Username & Password' }]; + + const [selectedAuthenticationMethod, setSelectedAuthenticationMethod] = useState( + authenticationOptions[0].value + ); + + const onAuthenticationMethodChange = (e) => { + setSelectedAuthenticationMethod(e.target.value); + }; + + const ConnectionConfigurationView = () => { + return ( + + + + + Data source name + + {dataConnection} + + + + Spark endpoint URL + + {'-'} + + + + + + + + Description + + {'-'} + + + + Authentication method + + {'-'} + + + + + + ); + }; + + const EditConnectionConfiguration = () => { + return ( + + + + ); + }; + + const saveChanges = () => { + http!.put(`${DATACONNECTIONS_BASE}`, { + body: JSON.stringify({ + name: props.dataConnection, + allowedRoles: props.allowedRoles, + connector: props.connector, + properties: props.properties, + }), + }); + setMode('view'); + }; + + const ConnectionConfigurationHeader = () => { + return ( + + + +

Data source configurations

+ Control configurations for your data source. +
+
+ + + setMode(mode === 'view' ? 'edit' : 'view')} + fill={mode === 'view' ? true : false} + > + {mode === 'view' ? 'Edit' : 'Cancel'} + + +
+ ); + }; + + return ( + <> + + + + + + + {mode === 'view' ? : } + + + {mode === 'edit' && ( + { + setMode('view'); + }} + onSave={saveChanges} + /> + )} + + + ); +}; diff --git a/public/components/data_connections/components/access_control_callout.tsx b/public/components/data_connections/components/connection_management_callout.tsx similarity index 89% rename from public/components/data_connections/components/access_control_callout.tsx rename to public/components/data_connections/components/connection_management_callout.tsx index f675673ffc..b788722872 100644 --- a/public/components/data_connections/components/access_control_callout.tsx +++ b/public/components/data_connections/components/connection_management_callout.tsx @@ -6,7 +6,7 @@ import { EuiCallOut } from '@elastic/eui'; import React from 'react'; -export const AccessControlCallout = () => { +export const ConnectionManagementCallout = () => { return ( Access to data can be managed in other systems outside of OpenSearch. Check with your diff --git a/public/components/data_connections/components/data_connection.tsx b/public/components/data_connections/components/data_connection.tsx index 0df41e30f9..0529d8529f 100644 --- a/public/components/data_connections/components/data_connection.tsx +++ b/public/components/data_connections/components/data_connection.tsx @@ -17,7 +17,6 @@ import { EuiAccordion, EuiIcon, EuiCard, - EuiTab, EuiTabbedContent, } from '@elastic/eui'; import React, { useEffect, useState } from 'react'; @@ -25,6 +24,7 @@ import { AccessControlTab } from './access_control_tab'; import { NoAccess } from './no_access'; import { DATACONNECTIONS_BASE } from '../../../../common/constants/shared'; import { coreRefs } from '../../../../public/framework/core_refs'; +import { ConnectionDetails } from './connection_details'; interface DatasourceDetails { allowedRoles: string[]; @@ -69,19 +69,11 @@ export const DataConnection = (props: any) => { }) ) .catch((err) => { - if (err.body.statusCode === 403) { - setHasAccess(false); - } + setHasAccess(false); }); }, [chrome, http]); const tabs = [ - { - id: 'data', - name: 'Data', - disabled: false, - content: <>, - }, { id: 'access_control', name: 'Access control', @@ -98,11 +90,18 @@ export const DataConnection = (props: any) => { id: 'connection_configuration', name: 'Connection configuration', disabled: false, - content: <>, + content: ( + + ), }, ]; - const renderOverview = () => { + const DatasourceOverview = () => { return ( @@ -115,11 +114,9 @@ export const DataConnection = (props: any) => { - Access control + Authentication method - {datasourceDetails.allowedRoles && datasourceDetails.allowedRoles.length - ? datasourceDetails.allowedRoles - : '-'} + {'-'} @@ -127,15 +124,27 @@ export const DataConnection = (props: any) => { - Connection description + Data source description - {datasourceDetails.name || '-'} + {'-'} + + + + Query permissions + + {datasourceDetails.allowedRoles && datasourceDetails.allowedRoles.length + ? 'Restricted' + : 'Everyone'} + + + + - Connection status + Spark data location - {datasourceDetails.cluster || '-'} + {'-'} @@ -165,7 +174,7 @@ export const DataConnection = (props: any) => { - {renderOverview()} + { const { http, chrome, pplService } = props; - const [data, setData] = useState([]); - const [hasAccess, setHasAccess] = useState(true); + const { setToast } = useToast(); + + const [data, setData] = useState([]); + const [isModalVisible, setIsModalVisible] = useState(false); + const [modalLayout, setModalLayout] = useState(); + + const deleteConnection = (connectionName: string) => { + http! + .delete(`${DATACONNECTIONS_BASE}/${connectionName}`) + .then(() => { + setToast(`Data connection ${connectionName} deleted successfully`); + setData( + data.filter((connection) => { + return !(connection.name === connectionName); + }) + ); + }) + .catch((err) => { + setToast(`Data connection $${connectionName} not deleted. See output for more details.`); + }); + }; useEffect(() => { chrome.setBreadcrumbs([ @@ -54,6 +74,23 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { ); } + const displayDeleteModal = (connectionName: string) => { + setModalLayout( + { + setIsModalVisible(false); + deleteConnection(connectionName); + }} + onCancel={() => { + setIsModalVisible(false); + }} + title={`Delete ${connectionName}`} + message={`Are you sure you want to delete ${connectionName}?`} + /> + ); + setIsModalVisible(true); + }; + const icon = (record: DataConnection) => { switch (record.connectionType) { case 'OPENSEARCH': @@ -83,17 +120,6 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { ), }, - { - field: 'connectionStatus', - name: 'Connection Status', - sortable: true, - truncateText: true, - render: (value, record) => ( - - {_.truncate(record.creationDate, { length: 100 })} - - ), - }, { field: 'actions', name: 'Actions', @@ -103,7 +129,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { { - /* Delete Datasource*/ + displayDeleteModal(record.name); }} /> ), @@ -156,6 +182,7 @@ export const ManageDataConnectionsTable = (props: HomeProps) => { isSelectable={true} /> + {isModalVisible && modalLayout} ); diff --git a/public/components/data_connections/components/no_access.tsx b/public/components/data_connections/components/no_access.tsx index 5c07b28931..1766f7fe18 100644 --- a/public/components/data_connections/components/no_access.tsx +++ b/public/components/data_connections/components/no_access.tsx @@ -4,7 +4,6 @@ */ import { EuiButton, EuiEmptyPrompt, EuiPage, EuiText } from '@elastic/eui'; -import _ from 'lodash'; import React from 'react'; export const NoAccess = () => { @@ -16,7 +15,7 @@ export const NoAccess = () => { body={ { - 'Missing permissions to view connection details. Contact your administrator for permissions.' + 'You are missing permissions to view connection details. Contact your administrator for permissions.' } } diff --git a/public/components/data_connections/components/query_permissions.tsx b/public/components/data_connections/components/query_permissions.tsx index d983015fe4..eee8312a8e 100644 --- a/public/components/data_connections/components/query_permissions.tsx +++ b/public/components/data_connections/components/query_permissions.tsx @@ -23,10 +23,10 @@ import { PermissionsConfigurationProps } from '../../../../common/types/data_con export const QueryPermissionsConfiguration = (props: PermissionsConfigurationProps) => { const { roles, selectedRoles, setSelectedRoles } = props; - const [selectedRadio, setSelectedRadio] = useState( + const [selectedAccessLevel, setSelectedAccessLevel] = useState( selectedRoles.length ? QUERY_RESTRICTED : QUERY_ALL ); - const radios = [ + const accessLevelOptions = [ { id: QUERY_RESTRICTED, label: 'Restricted - accessible by users with specific OpenSearch roles', @@ -71,15 +71,15 @@ export const QueryPermissionsConfiguration = (props: PermissionsConfigurationPro setSelectedRadio(id)} + options={accessLevelOptions} + idSelected={selectedAccessLevel} + onChange={(id) => setSelectedAccessLevel(id)} name="query-radio-group" legend={{ children: Access level, }} /> - {selectedRadio === QUERY_RESTRICTED && } + {selectedAccessLevel === QUERY_RESTRICTED && } diff --git a/public/components/data_connections/components/save_or_cancel.tsx b/public/components/data_connections/components/save_or_cancel.tsx new file mode 100644 index 0000000000..ccb9662101 --- /dev/null +++ b/public/components/data_connections/components/save_or_cancel.tsx @@ -0,0 +1,32 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiBottomBar, EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; + +interface SaveOrCancelProps { + onSave: () => void; + onCancel: () => void; +} + +export const SaveOrCancel = (props: SaveOrCancelProps) => { + const { onSave, onCancel } = props; + return ( + + + + + Discard change(s) + + + + + Save + + + + + ); +}; diff --git a/server/adaptors/ppl_plugin.ts b/server/adaptors/ppl_plugin.ts index ddc2a2ccf9..563c436726 100644 --- a/server/adaptors/ppl_plugin.ts +++ b/server/adaptors/ppl_plugin.ts @@ -55,6 +55,19 @@ export const PPLPlugin = function (Client, config, components) { method: 'GET', }); + ppl.deleteDataConnection = ca({ + url: { + fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}/<%=dataconnection%>`, + req: { + dataconnection: { + type: 'string', + required: true, + }, + }, + }, + method: 'DELETE', + }); + ppl.modifyDataConnection = ca({ url: { fmt: `${OPENSEARCH_DATACONNECTIONS_API.DATACONNECTION}`, diff --git a/server/routes/data_connections/data_connections_router.ts b/server/routes/data_connections/data_connections_router.ts index b0f2b2bade..a65660ba4a 100644 --- a/server/routes/data_connections/data_connections_router.ts +++ b/server/routes/data_connections/data_connections_router.ts @@ -37,6 +37,35 @@ export function registerDataConnectionsRoute(router: IRouter) { } ); + router.delete( + { + path: `${DATACONNECTIONS_BASE}/{name}`, + validate: { + params: schema.object({ + name: schema.string(), + }), + }, + }, + async (context, request, response): Promise => { + try { + const dataConnectionsresponse = await context.observability_plugin.observabilityClient + .asScoped(request) + .callAsCurrentUser('ppl.deleteDataConnection', { + dataconnection: request.params.name, + }); + return response.ok({ + body: dataConnectionsresponse, + }); + } catch (error: any) { + console.error('Issue in deleting data connection:', error); + return response.custom({ + statusCode: error.statusCode || 500, + body: error.message, + }); + } + } + ); + router.put( { path: `${DATACONNECTIONS_BASE}`, diff --git a/test/datasources.ts b/test/datasources.ts new file mode 100644 index 0000000000..1bdf6e25b6 --- /dev/null +++ b/test/datasources.ts @@ -0,0 +1,781 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const showDataConnectionsData = { + schema: [ + { + name: 'DATASOURCE_NAME', + type: 'string', + }, + { + name: 'CONNECTOR_TYPE', + type: 'string', + }, + ], + datarows: [ + ['my_spark_actual', 'SPARK'], + ['@opensearch', 'OPENSEARCH'], + ['my_spark', 'SPARK'], + ], + total: 3, + size: 3, + jsonData: [ + { + DATASOURCE_NAME: 'my_spark3', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark4', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark', + CONNECTOR_TYPE: 'SPARK', + }, + { + DATASOURCE_NAME: 'my_spark2', + CONNECTOR_TYPE: 'SPARK', + }, + ], +}; + +export const describeDataConnection = { + name: 'my_spark3', + connector: 'SPARK', + allowedRoles: [], + properties: { + 'spark.connector': 'emr', + 'spark.datasource.flint.host': '0.0.0.0', + 'spark.datasource.flint.integration': + 'https://aws.oss.sonatype.org/content/repositories/snapshots/org/opensearch/opensearch-spark-standalone_2.12/0.1.0-SNAPSHOT/opensearch-spark-standalone_2.12-0.1.0-20230731.182705-3.jar', + 'spark.datasource.flint.port': '9200', + 'spark.datasource.flint.scheme': 'http', + 'emr.cluster': 'j-3UNQLT1MPBGLG', + }, +}; + +export const mockRoleData = { + total: 44, + data: { + security_analytics_ack_alerts: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/securityanalytics/alerts/*'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + observability_read_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/observability/get'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + kibana_user: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for a kibana user', + cluster_permissions: ['cluster_composite_ops'], + index_permissions: [ + { + index_patterns: [ + '.kibana', + '.kibana-6', + '.kibana_*', + '.opensearch_dashboards', + '.opensearch_dashboards-6', + '.opensearch_dashboards_*', + ], + fls: [], + masked_fields: [], + allowed_actions: ['delete', 'index', 'manage', 'read'], + }, + { + index_patterns: ['.tasks', '.management-beats', '*:.tasks', '*:.management-beats'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + ], + tenant_permissions: [], + static: true, + }, + own_index: { + reserved: true, + hidden: false, + description: 'Allow all for indices named like the current user', + cluster_permissions: ['cluster_composite_ops'], + index_permissions: [ + { + index_patterns: ['${user_name}'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + ], + tenant_permissions: [], + static: true, + }, + alerting_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/alerting/*', + 'cluster:admin/opensearch/alerting/*', + 'cluster:admin/opensearch/notifications/feature/publish', + 'cluster_monitor', + ], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/aliases/get', + 'indices:admin/mappings/get', + 'indices_monitor', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + snapshot_management_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/snapshot_management/policy/explain', + 'cluster:admin/opensearch/snapshot_management/policy/get', + 'cluster:admin/opensearch/snapshot_management/policy/search', + 'cluster:admin/repository/get', + 'cluster:admin/snapshot/get', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + all_access: { + reserved: true, + hidden: false, + description: 'Allow full access to all indices and all cluster APIs', + cluster_permissions: ['*'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['*'], + }, + ], + tenant_permissions: [ + { + tenant_patterns: ['*'], + allowed_actions: ['kibana_all_write'], + }, + ], + static: true, + }, + alerting_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/alerting/alerts/get', + 'cluster:admin/opendistro/alerting/destination/get', + 'cluster:admin/opendistro/alerting/monitor/get', + 'cluster:admin/opendistro/alerting/monitor/search', + 'cluster:admin/opensearch/alerting/findings/get', + 'cluster:admin/opensearch/alerting/workflow/get', + 'cluster:admin/opensearch/alerting/workflow_alerts/get', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + cross_cluster_replication_follower_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/plugins/replication/autofollow/update'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/plugins/replication/index/pause', + 'indices:admin/plugins/replication/index/resume', + 'indices:admin/plugins/replication/index/setup/validate', + 'indices:admin/plugins/replication/index/start', + 'indices:admin/plugins/replication/index/status_check', + 'indices:admin/plugins/replication/index/stop', + 'indices:admin/plugins/replication/index/update', + 'indices:data/write/plugins/replication/changes', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + manage_snapshots: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for managing snapshots', + cluster_permissions: ['manage_snapshots'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/create', 'indices:data/write/index'], + }, + ], + tenant_permissions: [], + static: true, + }, + logstash: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for logstash and beats', + cluster_permissions: [ + 'cluster:admin/ingest/pipeline/get', + 'cluster:admin/ingest/pipeline/put', + 'cluster_composite_ops', + 'cluster_monitor', + 'indices:admin/template/get', + 'indices:admin/template/put', + ], + index_permissions: [ + { + index_patterns: ['logstash-*'], + fls: [], + masked_fields: [], + allowed_actions: ['create_index', 'crud'], + }, + { + index_patterns: ['*beat*'], + fls: [], + masked_fields: [], + allowed_actions: ['crud', 'create_index'], + }, + ], + tenant_permissions: [], + static: true, + }, + observability_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/observability/create', + 'cluster:admin/opensearch/observability/delete', + 'cluster:admin/opensearch/observability/get', + 'cluster:admin/opensearch/observability/update', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + point_in_time_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['manage_point_in_time'], + }, + ], + tenant_permissions: [], + static: false, + }, + notifications_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/notifications/*'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + notifications_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/notifications/channels/get', + 'cluster:admin/opensearch/notifications/configs/get', + 'cluster:admin/opensearch/notifications/features', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + cross_cluster_replication_leader_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/plugins/replication/index/setup/validate', + 'indices:data/read/plugins/replication/changes', + 'indices:data/read/plugins/replication/file_chunk', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + knn_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/knn_get_model_action', + 'cluster:admin/knn_search_model_action', + 'cluster:admin/knn_stats_action', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + ppl_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/ppl'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/mappings/get', + 'indices:data/read/search*', + 'indices:monitor/settings/get', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + security_analytics_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/securityanalytics/alerts/get', + 'cluster:admin/opensearch/securityanalytics/correlations/findings', + 'cluster:admin/opensearch/securityanalytics/correlations/list', + 'cluster:admin/opensearch/securityanalytics/detector/get', + 'cluster:admin/opensearch/securityanalytics/detector/search', + 'cluster:admin/opensearch/securityanalytics/findings/get', + 'cluster:admin/opensearch/securityanalytics/mapping/get', + 'cluster:admin/opensearch/securityanalytics/mapping/view/get', + 'cluster:admin/opensearch/securityanalytics/rule/get', + 'cluster:admin/opensearch/securityanalytics/rule/search', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + security_analytics_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/securityanalytics/alerts/*', + 'cluster:admin/opensearch/securityanalytics/correlations/*', + 'cluster:admin/opensearch/securityanalytics/detector/*', + 'cluster:admin/opensearch/securityanalytics/findings/*', + 'cluster:admin/opensearch/securityanalytics/mapping/*', + 'cluster:admin/opensearch/securityanalytics/rule/*', + ], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/mapping/put', 'indices:admin/mappings/get'], + }, + ], + tenant_permissions: [], + static: false, + }, + knn_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/knn_delete_model_action', + 'cluster:admin/knn_get_model_action', + 'cluster:admin/knn_remove_model_from_cache_action', + 'cluster:admin/knn_search_model_action', + 'cluster:admin/knn_stats_action', + 'cluster:admin/knn_training_job_route_decision_info_action', + 'cluster:admin/knn_training_job_router_action', + 'cluster:admin/knn_training_model_action', + 'cluster:admin/knn_update_model_graveyard_action', + 'cluster:admin/knn_warmup_action', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + asynchronous_search_read_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opendistro/asynchronous_search/get'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + index_management_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/ism/*', + 'cluster:admin/opendistro/rollup/*', + 'cluster:admin/opendistro/transform/*', + 'cluster:admin/opensearch/controlcenter/lron/*', + 'cluster:admin/opensearch/notifications/channels/get', + 'cluster:admin/opensearch/notifications/feature/publish', + ], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/opensearch/ism/*'], + }, + ], + tenant_permissions: [], + static: false, + }, + readall_and_monitor: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for to readall indices and monitor the cluster', + cluster_permissions: ['cluster_composite_ops_ro', 'cluster_monitor'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['read'], + }, + ], + tenant_permissions: [], + static: true, + }, + ml_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/ml/connectors/get', + 'cluster:admin/opensearch/ml/connectors/search', + 'cluster:admin/opensearch/ml/model_groups/search', + 'cluster:admin/opensearch/ml/models/get', + 'cluster:admin/opensearch/ml/models/search', + 'cluster:admin/opensearch/ml/tasks/get', + 'cluster:admin/opensearch/ml/tasks/search', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + security_rest_api_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'restapi:admin/actiongroups', + 'restapi:admin/allowlist', + 'restapi:admin/internalusers', + 'restapi:admin/nodesdn', + 'restapi:admin/roles', + 'restapi:admin/rolesmapping', + 'restapi:admin/ssl/certs/info', + 'restapi:admin/ssl/certs/reload', + 'restapi:admin/tenants', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + kibana_read_only: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + cross_cluster_search_remote_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/shards/search_shards', 'indices:data/read/search'], + }, + ], + tenant_permissions: [], + static: false, + }, + reports_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/reports/definition/get', + 'cluster:admin/opendistro/reports/definition/list', + 'cluster:admin/opendistro/reports/instance/get', + 'cluster:admin/opendistro/reports/instance/list', + 'cluster:admin/opendistro/reports/menu/download', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + anomaly_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/ad/detector/info', + 'cluster:admin/opendistro/ad/detector/search', + 'cluster:admin/opendistro/ad/detector/validate', + 'cluster:admin/opendistro/ad/detectors/get', + 'cluster:admin/opendistro/ad/result/search', + 'cluster:admin/opendistro/ad/result/topAnomalies', + 'cluster:admin/opendistro/ad/tasks/search', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + anomaly_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opendistro/ad/*', 'cluster_monitor'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: [ + 'indices:admin/aliases/get', + 'indices:admin/mappings/get', + 'indices_monitor', + ], + }, + ], + tenant_permissions: [], + static: false, + }, + reports_instances_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/reports/instance/get', + 'cluster:admin/opendistro/reports/instance/list', + 'cluster:admin/opendistro/reports/menu/download', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + snapshot_management_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opensearch/notifications/feature/publish', + 'cluster:admin/opensearch/snapshot_management/*', + 'cluster:admin/repository/*', + 'cluster:admin/snapshot/*', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + readall: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for to readall indices', + cluster_permissions: ['cluster_composite_ops_ro'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['read'], + }, + ], + tenant_permissions: [], + static: true, + }, + asynchronous_search_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opendistro/asynchronous_search/*'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:data/read/search*'], + }, + ], + tenant_permissions: [], + static: false, + }, + ml_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/opensearch/ml/*', 'cluster_monitor'], + index_permissions: [ + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_monitor'], + }, + ], + tenant_permissions: [], + static: false, + }, + reports_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/reports/definition/create', + 'cluster:admin/opendistro/reports/definition/delete', + 'cluster:admin/opendistro/reports/definition/get', + 'cluster:admin/opendistro/reports/definition/list', + 'cluster:admin/opendistro/reports/definition/on_demand', + 'cluster:admin/opendistro/reports/definition/update', + 'cluster:admin/opendistro/reports/instance/get', + 'cluster:admin/opendistro/reports/instance/list', + 'cluster:admin/opendistro/reports/menu/download', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + security_rest_api_access: { + reserved: true, + hidden: false, + cluster_permissions: [], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + ip2geo_datasource_read_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/geospatial/datasource/get'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + alerting_ack_alerts: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/alerting/alerts/*', + 'cluster:admin/opendistro/alerting/chained_alerts/*', + 'cluster:admin/opendistro/alerting/workflow_alerts/*', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + ip2geo_datasource_full_access: { + reserved: true, + hidden: false, + cluster_permissions: ['cluster:admin/geospatial/datasource/*'], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + kibana_server: { + reserved: true, + hidden: false, + description: 'Provide the minimum permissions for the Kibana server', + cluster_permissions: [ + 'cluster_composite_ops', + 'cluster_monitor', + 'indices:admin/index_template*', + 'indices:admin/template*', + 'indices:data/read/scroll*', + 'manage_point_in_time', + ], + index_permissions: [ + { + index_patterns: ['.kibana', '.opensearch_dashboards'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.kibana-6', '.opensearch_dashboards-6'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.kibana_*', '.opensearch_dashboards_*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.tasks'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['.management-beats*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices_all'], + }, + { + index_patterns: ['*'], + fls: [], + masked_fields: [], + allowed_actions: ['indices:admin/aliases*'], + }, + ], + tenant_permissions: [], + static: true, + }, + notebooks_read_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/notebooks/get', + 'cluster:admin/opendistro/notebooks/list', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + notebooks_full_access: { + reserved: true, + hidden: false, + cluster_permissions: [ + 'cluster:admin/opendistro/notebooks/create', + 'cluster:admin/opendistro/notebooks/delete', + 'cluster:admin/opendistro/notebooks/get', + 'cluster:admin/opendistro/notebooks/list', + 'cluster:admin/opendistro/notebooks/update', + ], + index_permissions: [], + tenant_permissions: [], + static: false, + }, + }, +};