From e33907e762b5730b6524da474fda05ffbee18bda Mon Sep 17 00:00:00 2001 From: Darshit Chanpura Date: Thu, 14 Mar 2024 11:54:41 -0400 Subject: [PATCH 01/27] Consume changes from main, fixes linter and fixes tests Signed-off-by: Darshit Chanpura --- ...ess-test-multidatasources-disabled-e2e.yml | 49 +++++++ ...ress-test-multidatasources-enabled-e2e.yml | 120 ++++++++++++++++++ opensearch_dashboards.json | 4 +- public/apps/configuration/app-router.tsx | 18 ++- .../apps/configuration/configuration-app.tsx | 16 ++- .../apps/configuration/panels/get-started.tsx | 14 +- .../__snapshots__/get-started.test.tsx.snap | 36 ++++++ .../configuration/test/top-nav-menu.test.tsx | 81 ++++++++++++ public/apps/configuration/top-nav-menu.tsx | 51 ++++++++ .../apps/configuration/utils/request-utils.ts | 4 +- public/apps/types.ts | 5 +- public/plugin.ts | 9 +- public/types.ts | 4 + server/backend/opensearch_security_client.ts | 2 +- server/plugin.ts | 16 ++- server/routes/index.ts | 46 +++++-- .../multi_datasources_disabled.spec.js | 28 ++++ .../multi_datasources_enabled.spec.js | 39 ++++++ test/cypress/support/commands.js | 11 ++ .../security_entity_api.test.ts | 6 +- 20 files changed, 528 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/cypress-test-multidatasources-disabled-e2e.yml create mode 100644 .github/workflows/cypress-test-multidatasources-enabled-e2e.yml create mode 100644 public/apps/configuration/test/top-nav-menu.test.tsx create mode 100644 public/apps/configuration/top-nav-menu.tsx create mode 100644 test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js create mode 100644 test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js diff --git a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml new file mode 100644 index 000000000..8079a2410 --- /dev/null +++ b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml @@ -0,0 +1,49 @@ +name: E2E multi datasources disabled workflow + +on: [ push, pull_request ] + +env: + OPENSEARCH_VERSION: '3.0.0' + CI: 1 + # avoid warnings like "tput: No value for $TERM and no -T specified" + TERM: xterm + PLUGIN_NAME: opensearch-security + OPENSEARCH_INITIAL_ADMIN_PASSWORD: myStrongPassword123! + +jobs: + tests: + name: Run Cypress multidatasources tests + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout Branch + uses: actions/checkout@v3 + + # Configure the Dashboard for multi datasources disabled (default) + - name: Create OpenSearch Dashboards Config + if: ${{ runner.os == 'Linux' }} + run: | + cat << 'EOT' > opensearch_dashboards_multidatasources.yml + server.host: "localhost" + opensearch.hosts: ["https://localhost:9200"] + opensearch.ssl.verificationMode: none + opensearch.username: "kibanaserver" + opensearch.password: "kibanaserver" + opensearch.requestHeadersWhitelist: [ authorization,securitytenant ] + opensearch_security.multitenancy.enabled: false + opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"] + opensearch_security.readonly_mode.roles: ["kibana_read_only"] + opensearch_security.cookie.secure: false + data_source.enabled: false + home.disableWelcomeScreen: true + EOT + + - name: Run Cypress Tests + uses: ./.github/actions/run-cypress-tests + with: + dashboards_config_file: opensearch_dashboards_multidatasources.yml + yarn_command: 'yarn cypress:run --browser chrome --headless --spec "test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js"' diff --git a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml new file mode 100644 index 000000000..e02c260c8 --- /dev/null +++ b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml @@ -0,0 +1,120 @@ +name: E2E multi datasources enabled workflow + +on: [ push, pull_request ] + +env: + OPENSEARCH_VERSION: '3.0.0' + CI: 1 + # avoid warnings like "tput: No value for $TERM and no -T specified" + TERM: xterm + PLUGIN_NAME: opensearch-security + OPENSEARCH_INITIAL_ADMIN_PASSWORD: myStrongPassword123! + +jobs: + tests: + name: Run Cypress multidatasources tests + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout Branch + uses: actions/checkout@v3 + + - name: Set env + run: | + opensearch_version=$(node -p "require('./package.json').opensearchDashboards.version") + plugin_version=$(node -p "require('./package.json').version") + echo "OPENSEARCH_VERSION=$opensearch_version" >> $GITHUB_ENV + echo "PLUGIN_VERSION=$plugin_version" >> $GITHUB_ENV + shell: bash + + - name: Create remote OpenSearch Config + if: ${{ runner.os == 'Linux' }} + run: | + cat << 'EOT' > remote_opensearch.yml + http.port: 9202 + plugins.security.ssl.transport.pemcert_filepath: esnode.pem + plugins.security.ssl.transport.pemkey_filepath: esnode-key.pem + plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem + plugins.security.ssl.transport.enforce_hostname_verification: false + plugins.security.ssl.http.pemcert_filepath: esnode.pem + plugins.security.ssl.http.pemkey_filepath: esnode-key.pem + plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem + plugins.security.allow_unsafe_democertificates: true + plugins.security.allow_default_init_securityindex: true + plugins.security.authcz.admin_dn: + - 'CN=A,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA' + plugins.security.nodes_dn: + - 'CN=node1.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA' + - 'CN=node2.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA' + plugins.security.audit.type: internal_opensearch + plugins.security.enable_snapshot_restore_privilege: true + plugins.security.check_snapshot_restore_write_privileges: true + # TODO: change this back to true/just append to the created opensearch.yml the new port + # after the self-signed certs issue is fixed + plugins.security.ssl.http.enabled: false + plugins.security.restapi.roles_enabled: [all_access, security_rest_api_access] + plugins.security.system_indices.enabled: true + plugins.security.system_indices.indices: [.plugins-ml-config, .plugins-ml-connector, + .plugins-ml-model-group, .plugins-ml-model, .plugins-ml-task, .plugins-ml-conversation-meta, + .plugins-ml-conversation-interactions, .plugins-ml-memory-meta, .plugins-ml-memory-message, + .opendistro-alerting-config, .opendistro-alerting-alert*, .opendistro-anomaly-results*, + .opendistro-anomaly-detector*, .opendistro-anomaly-checkpoints, .opendistro-anomaly-detection-state, + .opendistro-reports-*, .opensearch-notifications-*, .opensearch-notebooks, .opensearch-observability, + .ql-datasources, .opendistro-asynchronous-search-response*, .replication-metadata-store, + .opensearch-knn-models, .geospatial-ip2geo-data*, .plugins-flow-framework-config, + .plugins-flow-framework-templates, .plugins-flow-framework-state] + node.max_local_storage_nodes: 3 + EOT + + - name: Download security plugin and create setup scripts + uses: ./.github/actions/download-plugin + with: + opensearch-version: ${{ env.OPENSEARCH_VERSION }} + plugin-name: ${{ env.PLUGIN_NAME }} + plugin-version: ${{ env.PLUGIN_VERSION }} + + - name: Run Opensearch with A Single Plugin + uses: derek-ho/start-opensearch@9202 + with: + opensearch-version: ${{ env.OPENSEARCH_VERSION }} + plugins: "file:$(pwd)/opensearch-security.zip" + security-enabled: true + admin-password: ${{ env.OPENSEARCH_INITIAL_ADMIN_PASSWORD }} + security_config_file: ${{ inputs.security_config_file }} + opensearch_yml_file: remote_opensearch.yml + opensearch_port: 9202 + + - name: Check OpenSearch is running + # Verify that the server is operational + run: | + curl http://localhost:9202/_cat/plugins -v -u admin:myStrongPassword123! + shell: bash + + # Configure the Dashboard for multi datasources + - name: Create OpenSearch Dashboards Config + if: ${{ runner.os == 'Linux' }} + run: | + cat << 'EOT' > opensearch_dashboards_multidatasources.yml + server.host: "localhost" + opensearch.hosts: ["https://localhost:9200"] + opensearch.ssl.verificationMode: none + opensearch.username: "kibanaserver" + opensearch.password: "kibanaserver" + opensearch.requestHeadersWhitelist: [ authorization,securitytenant ] + opensearch_security.multitenancy.enabled: true + opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"] + opensearch_security.readonly_mode.roles: ["kibana_read_only"] + opensearch_security.cookie.secure: false + data_source.enabled: true + home.disableWelcomeScreen: true + EOT + + - name: Run Cypress Tests + uses: ./.github/actions/run-cypress-tests + with: + dashboards_config_file: opensearch_dashboards_multidatasources.yml + yarn_command: 'yarn cypress:run --browser chrome --headless --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index 994096906..3a2642593 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -10,7 +10,9 @@ "savedObjectsManagement" ], "optionalPlugins": [ - "managementOverview" + "managementOverview", + "dataSource", + "dataSourceManagement" ], "server": true, "ui": true diff --git a/public/apps/configuration/app-router.tsx b/public/apps/configuration/app-router.tsx index 2e4ce7ca3..c4d58d3bc 100644 --- a/public/apps/configuration/app-router.tsx +++ b/public/apps/configuration/app-router.tsx @@ -15,7 +15,7 @@ import { EuiBreadcrumb, EuiPage, EuiPageBody, EuiPageSideBar } from '@elastic/eui'; import { flow, map, mapValues, partial } from 'lodash'; -import React from 'react'; +import React, { useState } from 'react'; import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; import { AppDependencies } from '../types'; import { AuditLogging } from './panels/audit-logging/audit-logging'; @@ -40,6 +40,8 @@ import { Action, RouteItem, SubAction } from './types'; import { ResourceType } from '../../../common'; import { buildHashUrl, buildUrl } from './utils/url-builder'; import { CrossPageToast } from './cross-page-toast'; +import { useOpenSearchDashboards } from '../../../../../src/plugins/opensearch_dashboards_react/public'; +import { SecurityPluginTopNavMenu, TopNavMenu } from './top-nav-menu'; const LANDING_PAGE_URL = '/getstarted'; @@ -145,6 +147,7 @@ function decodeParams(params: { [k: string]: string }): any { export function AppRouter(props: AppDependencies) { const setGlobalBreadcrumbs = flow(getBreadcrumbs, props.coreStart.chrome.setBreadcrumbs); + const [datasourceId, setDatasourceId] = useState(undefined); return ( @@ -255,14 +258,23 @@ export function AppRouter(props: AppDependencies) { path={ROUTE_MAP.tenants.href} render={() => { setGlobalBreadcrumbs(ResourceType.tenants); - return ; + return ( + <> + + + ); }} /> { setGlobalBreadcrumbs(ResourceType.tenants); - return ; + + return ( + <> + + + ); }} /> diff --git a/public/apps/configuration/panels/get-started.tsx b/public/apps/configuration/panels/get-started.tsx index 806d8d2f4..ffc29aa97 100644 --- a/public/apps/configuration/panels/get-started.tsx +++ b/public/apps/configuration/panels/get-started.tsx @@ -26,8 +26,9 @@ import { EuiTitle, EuiGlobalToastList, } from '@elastic/eui'; -import React from 'react'; +import React, { useState } from 'react'; import { FormattedMessage } from '@osd/i18n/react'; +import { setData } from 'src/plugins/vis_type_vega/public/services'; import { AppDependencies } from '../../types'; import { buildHashUrl } from '../utils/url-builder'; import { Action } from '../types'; @@ -159,6 +160,8 @@ const setOfSteps = [ ]; export function GetStarted(props: AppDependencies) { + const [datasourceId, setDatasourceId] = useState(undefined); + let steps; if (props.config.ui.backend_configurable) { steps = [addBackendStep, ...setOfSteps]; @@ -170,6 +173,11 @@ export function GetStarted(props: AppDependencies) { return ( <>
+

Get started

@@ -236,7 +244,9 @@ export function GetStarted(props: AppDependencies) { data-test-subj="purge-cache" onClick={async () => { try { - await httpDelete(props.coreStart.http, API_ENDPOINT_CACHE); + await httpDelete(props.coreStart.http, API_ENDPOINT_CACHE, { + dataSourceId: datasourceId, + }); addToast( createSuccessToast( 'cache-flush-success', diff --git a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap index 82c3ec0b8..443b93e32 100644 --- a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap +++ b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap @@ -5,6 +5,24 @@ exports[`Get started (landing page) renders when backend configuration is disabl
+ + { + const coreStartMock = { + savedObjects: { + client: jest.fn(), + }, + notifications: jest.fn(), + }; + + const dataSourceMenuMock = jest.fn(() =>
Mock DataSourceMenu
); + + const dataSourceManagementMock = { + ui: { + DataSourceMenu: dataSourceMenuMock, + }, + }; + + it('renders DataSourceMenu when dataSource is enabled', () => { + const securityPluginStartDepsMock = { + dataSource: { + dataSourceEnabled: true, + }, + }; + + const wrapper = render( + {}} + /> + ); + + expect(dataSourceMenuMock).toBeCalled(); + expect(wrapper.html()).not.toBe(''); + }); + + it('renders null when dataSource is disabled', () => { + const securityPluginStartDepsMock = { + dataSource: { + dataSourceEnabled: false, + }, + }; + + const wrapper = render( + {}} + /> + ); + + expect(dataSourceMenuMock).not.toBeCalled(); + expect(wrapper.html()).toBe(''); + }); +}); diff --git a/public/apps/configuration/top-nav-menu.tsx b/public/apps/configuration/top-nav-menu.tsx new file mode 100644 index 000000000..75821cd77 --- /dev/null +++ b/public/apps/configuration/top-nav-menu.tsx @@ -0,0 +1,51 @@ +/* + * Copyright OpenSearch Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import React from 'react'; +import { CoreStart } from 'opensearch-dashboards/public'; +import { NavigationPublicPluginStart } from 'src/plugins/navigation/public/types'; +import { ClientConfigType } from '../../types'; +import { PLUGIN_NAME } from '../../../common'; +import { AppDependencies } from '../types'; + +export interface TopNavMenuProps extends AppDependencies { + dataSourcePickerReadOnly: boolean; + random: any; +} + +export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { + const { + coreStart, + securityPluginStartDeps, + dataSourcePickerReadOnly, + setHeaderActionMenu, + dataSourceManagement, + } = props; + const DataSourceMenu = dataSourceManagement?.ui.DataSourceMenu; + const dataSourceEnabled = !!securityPluginStartDeps.dataSource?.dataSourceEnabled; + + return dataSourceEnabled ? ( + {}} + hideLocalCluster={false} + fullWidth={false} + /> + ) : null; +}; diff --git a/public/apps/configuration/utils/request-utils.ts b/public/apps/configuration/utils/request-utils.ts index f348f49ad..20502309f 100644 --- a/public/apps/configuration/utils/request-utils.ts +++ b/public/apps/configuration/utils/request-utils.ts @@ -34,8 +34,8 @@ export async function httpPut(http: HttpStart, url: string, body?: object): P return await request(http.put, url, body); } -export async function httpDelete(http: HttpStart, url: string): Promise { - return await request(http.delete, url); +export async function httpDelete(http: HttpStart, url: string, body?: object): Promise { + return await request(http.delete, url, body); } /** diff --git a/public/apps/types.ts b/public/apps/types.ts index 43d723563..d92e63842 100644 --- a/public/apps/types.ts +++ b/public/apps/types.ts @@ -13,15 +13,18 @@ * permissions and limitations under the License. */ +import { DataSourceManagementPluginSetup } from '../../../../src/plugins/data_source_management/public'; import { AppMountParameters, CoreStart } from '../../../../src/core/public'; import { SecurityPluginStartDependencies, ClientConfigType, DashboardsInfo } from '../types'; export interface AppDependencies { coreStart: CoreStart; - navigation: SecurityPluginStartDependencies; + securityPluginStartDeps: SecurityPluginStartDependencies; params: AppMountParameters; config: ClientConfigType; dashboardsInfo: DashboardsInfo; + setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; + dataSourceManagement: DataSourceManagementPluginSetup; } export interface BreadcrumbsPageDependencies extends AppDependencies { diff --git a/public/plugin.ts b/public/plugin.ts index 7ac039fb1..a8b4fea5e 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -112,7 +112,14 @@ export class SecurityPlugin excludeFromDisabledTransportCategories(config.disabledTransportCategories.exclude); excludeFromDisabledRestCategories(config.disabledRestCategories.exclude); - return renderApp(coreStart, depsStart as SecurityPluginStartDependencies, params, config); + return renderApp( + coreStart, + depsStart as SecurityPluginStartDependencies, + params, + config, + params.setHeaderActionMenu, + deps.dataSourceManagement + ); }, category: DEFAULT_APP_CATEGORIES.management, }); diff --git a/public/types.ts b/public/types.ts index 4acfc442f..f9dd312df 100644 --- a/public/types.ts +++ b/public/types.ts @@ -19,6 +19,8 @@ import { SavedObjectsManagementPluginStart, } from '../../../src/plugins/saved_objects_management/public'; import { ManagementOverViewPluginSetup } from '../../../src/plugins/management_overview/public'; +import { DataSourcePluginStart } from '../../../src/plugins/data_source/public/types'; +import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface SecurityPluginSetup {} @@ -28,11 +30,13 @@ export interface SecurityPluginStart {} export interface SecurityPluginSetupDependencies { savedObjectsManagement: SavedObjectsManagementPluginSetup; managementOverview?: ManagementOverViewPluginSetup; + dataSourceManagement?: DataSourceManagementPluginSetup; } export interface SecurityPluginStartDependencies { navigation: NavigationPublicPluginStart; savedObjectsManagement: SavedObjectsManagementPluginStart; + dataSource: DataSourcePluginStart; } export interface AuthInfo { diff --git a/server/backend/opensearch_security_client.ts b/server/backend/opensearch_security_client.ts index 7897444e4..1da9a0f46 100755 --- a/server/backend/opensearch_security_client.ts +++ b/server/backend/opensearch_security_client.ts @@ -19,7 +19,7 @@ import { getAuthInfo } from '../../public/utils/auth-info-utils'; import { TenancyConfigSettings } from '../../public/apps/configuration/panels/tenancy-config/types'; export class SecurityClient { - constructor(private readonly esClient: ILegacyClusterClient) {} + constructor(private readonly esClient: ILegacyClusterClient | undefined) {} public async authenticate(request: OpenSearchDashboardsRequest, credentials: any): Promise { const authHeader = Buffer.from(`${credentials.username}:${credentials.password}`).toString( diff --git a/server/plugin.ts b/server/plugin.ts index 5f5f50913..e7877ad62 100644 --- a/server/plugin.ts +++ b/server/plugin.ts @@ -46,12 +46,19 @@ import { createMigrationOpenSearchClient } from '../../../src/core/server/saved_ import { SecuritySavedObjectsClientWrapper } from './saved_objects/saved_objects_wrapper'; import { addTenantParameterToResolvedShortLink } from './multitenancy/tenant_resolver'; import { ReadonlyService } from './readonly/readonly_service'; +import { DataSourceManagementPlugin } from '../../../src/plugins/data_source_management/public/plugin'; +import { DataSourcePluginSetup } from '../../../src/plugins/data_source/server/types'; export interface SecurityPluginRequestContext { logger: Logger; esClient: ILegacyClusterClient; } +export interface SecurityPluginSetupDependencies { + dataSourceManagement: ReturnType; + dataSource: DataSourcePluginSetup; +} + declare module 'opensearch-dashboards/server' { interface RequestHandlerContext { security_plugin: SecurityPluginRequestContext; @@ -83,8 +90,9 @@ export class SecurityPlugin implements Plugin(); const config: SecurityPluginConfigType = await config$.pipe(first()).toPromise(); @@ -97,6 +105,10 @@ export class SecurityPlugin implements Plugin { - const client = context.security_plugin.esClient.asScoped(request); - let esResponse; - try { - esResponse = await client.callAsCurrentUser('opensearch_security.clearCache'); - return response.ok({ - body: { - message: esResponse.message, - }, - }); - } catch (error) { - return errorResponse(response, error); + if (!dataSourceEnabled || !request.body?.dataSourceId) { + const client = context.security_plugin.esClient.asScoped(request); + let esResponse; + try { + esResponse = await client.callAsCurrentUser('opensearch_security.clearCache'); + return response.ok({ + body: { + message: esResponse.message, + }, + }); + } catch (error) { + return errorResponse(response, error); + } + } else { + const client = context.dataSource.opensearch.legacy.getClient(request.body?.dataSourceId); + let esResponse; + try { + esResponse = await client.callAPI('opensearch_security.clearCache', {}); + console.log(esResponse); + return response.ok({ + body: { + message: 'test', + }, + }); + } catch (error) { + return errorResponse(response, error); + } } } ); diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js new file mode 100644 index 000000000..ac20b56cd --- /dev/null +++ b/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js @@ -0,0 +1,28 @@ +/* + * Copyright OpenSearch Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { loginWithBasicAuth } from '../../support/commands'; + +describe('Multi-datasources enabled', () => { + it('Sanity checks the cluster selector is not visible when multi datasources is disabled', () => { + loginWithBasicAuth(); + + cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted', { + failOnStatusCode: false, + }); + + cy.get('[data-test-subj="dataSourceSelectableContextMenuHeaderLink"]').should('not.exist'); + }); +}); diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js new file mode 100644 index 000000000..149aa3ebf --- /dev/null +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -0,0 +1,39 @@ +/* + * Copyright OpenSearch Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import { loginWithBasicAuth } from '../../support/commands'; + +const createDataSource = () => { + cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources/create'); + cy.get('[data-test-subj="createDataSourceFormTitleField"]').type('9202'); + cy.get('[data-test-subj="createDataSourceFormEndpointField"]').type('http://localhost:9202'); + cy.get('[data-test-subj="createDataSourceFormUsernameField"]').type('admin'); + cy.get('[data-test-subj="createDataSourceFormPasswordField"]').type('myStrongPassword123!'); + cy.get('[data-test-subj="createDataSourceTestConnectionButton"]').click(); + cy.get('.euiToastHeader__title').should('contain', 'successful'); + cy.get('[data-test-subj="createDataSourceButton"]').click(); +}; + +describe('Multi-datasources enabled', () => { + it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { + loginWithBasicAuth(); + createDataSource(); + + cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); + + cy.get('[data-test-subj="dataSourceSelectableContextMenuHeaderLink"]').click(); + cy.contains('9202'); + }); +}); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 29c565062..818933049 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -91,6 +91,17 @@ Cypress.Commands.add('loginWithSamlMultiauth', () => { cy.get('button[id=btn-sign-in]').should('be.visible').click(); }); +export const loginWithBasicAuth = () => { + cy.visit('http://localhost:5601', { + failOnStatusCode: false, + }); + cy.get('[data-test-subj="user-name"]').type('admin'); + cy.get('[data-test-subj="password"]').type('myStrongPassword123!'); + cy.get('[data-test-subj="submit"]').click(); + localStorage.setItem('opendistro::security::tenant::saved', '""'); + localStorage.setItem('home:newThemeModal:show', 'false'); +}; + Cypress.Commands.add('shortenUrl', (data, tenant) => { cy.request({ url: `http://localhost:5601${DASHBOARDS_API.SHORTEN_URL}`, diff --git a/test/jest_integration/security_entity_api.test.ts b/test/jest_integration/security_entity_api.test.ts index f28817798..dc84e3303 100644 --- a/test/jest_integration/security_entity_api.test.ts +++ b/test/jest_integration/security_entity_api.test.ts @@ -351,14 +351,16 @@ describe('start OpenSearch Dashboards server', () => { it('delete cache', async () => { const deleteCacheResponse = await osdTestServer.request .delete(root, '/api/v1/configuration/cache') - .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS); + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ dataSourceId: '' }); expect(deleteCacheResponse.status).toEqual(200); const adminAuthCookie = await getAuthCookie(root, ADMIN_USER, ADMIN_PASSWORD); const deleteCacheWithCookieResponse = await osdTestServer.request .delete(root, '/api/v1/configuration/cache') .unset(AUTHORIZATION_HEADER_NAME) - .set('Cookie', adminAuthCookie); + .set('Cookie', adminAuthCookie) + .send({ dataSourceId: '' }); expect(deleteCacheWithCookieResponse.status).toEqual(200); }); From a4359c920dc5e8e2c8d723304f51b7b54a8ceea1 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 13:36:13 -0400 Subject: [PATCH 02/27] Remove undefined Signed-off-by: Derek Ho --- server/backend/opensearch_security_client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/backend/opensearch_security_client.ts b/server/backend/opensearch_security_client.ts index 1da9a0f46..7897444e4 100755 --- a/server/backend/opensearch_security_client.ts +++ b/server/backend/opensearch_security_client.ts @@ -19,7 +19,7 @@ import { getAuthInfo } from '../../public/utils/auth-info-utils'; import { TenancyConfigSettings } from '../../public/apps/configuration/panels/tenancy-config/types'; export class SecurityClient { - constructor(private readonly esClient: ILegacyClusterClient | undefined) {} + constructor(private readonly esClient: ILegacyClusterClient) {} public async authenticate(request: OpenSearchDashboardsRequest, credentials: any): Promise { const authHeader = Buffer.from(`${credentials.username}:${credentials.password}`).toString( From 23db5315d24fe9178506dce52960ec75513d6ccc Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 13:43:33 -0400 Subject: [PATCH 03/27] Final cleanup Signed-off-by: Derek Ho --- public/apps/configuration/panels/get-started.tsx | 6 +++--- public/apps/configuration/top-nav-menu.tsx | 5 +++-- server/routes/index.ts | 3 +-- .../e2e/multi-datasources/multi_datasources_enabled.spec.js | 4 +++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/public/apps/configuration/panels/get-started.tsx b/public/apps/configuration/panels/get-started.tsx index ffc29aa97..e29581c59 100644 --- a/public/apps/configuration/panels/get-started.tsx +++ b/public/apps/configuration/panels/get-started.tsx @@ -28,7 +28,6 @@ import { } from '@elastic/eui'; import React, { useState } from 'react'; import { FormattedMessage } from '@osd/i18n/react'; -import { setData } from 'src/plugins/vis_type_vega/public/services'; import { AppDependencies } from '../../types'; import { buildHashUrl } from '../utils/url-builder'; import { Action } from '../types'; @@ -37,6 +36,7 @@ import { API_ENDPOINT_CACHE, DocLinks } from '../constants'; import { ExternalLink, ExternalLinkButton } from '../utils/display-utils'; import { httpDelete } from '../utils/request-utils'; import { createSuccessToast, createUnknownErrorToast, useToastState } from '../utils/toast-utils'; +import { SecurityPluginTopNavMenu } from '../top-nav-menu'; const addBackendStep = { title: 'Add backends', @@ -160,7 +160,7 @@ const setOfSteps = [ ]; export function GetStarted(props: AppDependencies) { - const [datasourceId, setDatasourceId] = useState(undefined); + const [datasourceId, setDatasourceId] = useState(''); let steps; if (props.config.ui.backend_configurable) { @@ -176,7 +176,7 @@ export function GetStarted(props: AppDependencies) { diff --git a/public/apps/configuration/top-nav-menu.tsx b/public/apps/configuration/top-nav-menu.tsx index 75821cd77..c2e95dab6 100644 --- a/public/apps/configuration/top-nav-menu.tsx +++ b/public/apps/configuration/top-nav-menu.tsx @@ -22,7 +22,7 @@ import { AppDependencies } from '../types'; export interface TopNavMenuProps extends AppDependencies { dataSourcePickerReadOnly: boolean; - random: any; + setDatasourceId: React.Dispatch>; } export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { @@ -32,6 +32,7 @@ export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { dataSourcePickerReadOnly, setHeaderActionMenu, dataSourceManagement, + setDatasourceId, } = props; const DataSourceMenu = dataSourceManagement?.ui.DataSourceMenu; const dataSourceEnabled = !!securityPluginStartDeps.dataSource?.dataSourceEnabled; @@ -43,7 +44,7 @@ export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { savedObjects={coreStart.savedObjects.client} setMenuMountPoint={setHeaderActionMenu} notifications={coreStart.notifications} - dataSourceCallBackFunc={() => {}} + dataSourceCallBackFunc={(datasource) => setDatasourceId(datasource.id)} hideLocalCluster={false} fullWidth={false} /> diff --git a/server/routes/index.ts b/server/routes/index.ts index f3d60fe24..017cf818d 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -770,10 +770,9 @@ export function defineRoutes(router: IRouter, dataSourceEnabled: boolean) { let esResponse; try { esResponse = await client.callAPI('opensearch_security.clearCache', {}); - console.log(esResponse); return response.ok({ body: { - message: 'test', + message: esResponse.message, }, }); } catch (error) { diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index 149aa3ebf..b4b06d370 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -34,6 +34,8 @@ describe('Multi-datasources enabled', () => { cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); cy.get('[data-test-subj="dataSourceSelectableContextMenuHeaderLink"]').click(); - cy.contains('9202'); + cy.contains('9202').click(); + cy.get('[data-test-subj="purge-cache"]').click(); + cy.get('.euiToastHeader__title').should('contain', 'successful'); }); }); From bfd8c417cc22388436a4dd87768e9b29c1532252 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 13:53:18 -0400 Subject: [PATCH 04/27] Fix snapshot with naming Signed-off-by: Derek Ho --- .../panels/test/__snapshots__/get-started.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap index 443b93e32..f56cadecd 100644 --- a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap +++ b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap @@ -21,7 +21,7 @@ exports[`Get started (landing page) renders when backend configuration is disabl dataSourcePickerReadOnly={false} navigation={Object {}} params={Object {}} - random={[Function]} + setDatasourceId={[Function]} /> Date: Thu, 14 Mar 2024 14:07:27 -0400 Subject: [PATCH 05/27] Revert file Signed-off-by: Derek Ho --- public/apps/configuration/app-router.tsx | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/public/apps/configuration/app-router.tsx b/public/apps/configuration/app-router.tsx index c4d58d3bc..e063463f0 100644 --- a/public/apps/configuration/app-router.tsx +++ b/public/apps/configuration/app-router.tsx @@ -14,8 +14,8 @@ */ import { EuiBreadcrumb, EuiPage, EuiPageBody, EuiPageSideBar } from '@elastic/eui'; -import { flow, map, mapValues, partial } from 'lodash'; -import React, { useState } from 'react'; +import { flow, partial } from 'lodash'; +import React from 'react'; import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; import { AppDependencies } from '../types'; import { AuditLogging } from './panels/audit-logging/audit-logging'; @@ -40,8 +40,6 @@ import { Action, RouteItem, SubAction } from './types'; import { ResourceType } from '../../../common'; import { buildHashUrl, buildUrl } from './utils/url-builder'; import { CrossPageToast } from './cross-page-toast'; -import { useOpenSearchDashboards } from '../../../../../src/plugins/opensearch_dashboards_react/public'; -import { SecurityPluginTopNavMenu, TopNavMenu } from './top-nav-menu'; const LANDING_PAGE_URL = '/getstarted'; @@ -147,7 +145,6 @@ function decodeParams(params: { [k: string]: string }): any { export function AppRouter(props: AppDependencies) { const setGlobalBreadcrumbs = flow(getBreadcrumbs, props.coreStart.chrome.setBreadcrumbs); - const [datasourceId, setDatasourceId] = useState(undefined); return ( @@ -258,23 +255,14 @@ export function AppRouter(props: AppDependencies) { path={ROUTE_MAP.tenants.href} render={() => { setGlobalBreadcrumbs(ResourceType.tenants); - return ( - <> - - - ); + return ; }} /> { setGlobalBreadcrumbs(ResourceType.tenants); - - return ( - <> - - - ); + return ; }} /> Date: Thu, 14 Mar 2024 14:27:26 -0400 Subject: [PATCH 06/27] Try to fix remote cypress test with more specific selector Signed-off-by: Derek Ho --- .../e2e/multi-datasources/multi_datasources_enabled.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index b4b06d370..8b04df641 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -29,12 +29,12 @@ const createDataSource = () => { describe('Multi-datasources enabled', () => { it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { loginWithBasicAuth(); - createDataSource(); + // createDataSource(); cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); cy.get('[data-test-subj="dataSourceSelectableContextMenuHeaderLink"]').click(); - cy.contains('9202').click(); + cy.contains('li.euiSelectableListItem', '9202').click(); cy.get('[data-test-subj="purge-cache"]').click(); cy.get('.euiToastHeader__title').should('contain', 'successful'); }); From f8765b273091a2283ce41babb7aa5b1fe3ca55c5 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 14:45:28 -0400 Subject: [PATCH 07/27] Revert local changes Signed-off-by: Derek Ho --- .../e2e/multi-datasources/multi_datasources_enabled.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index 8b04df641..f7d345b63 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -29,7 +29,7 @@ const createDataSource = () => { describe('Multi-datasources enabled', () => { it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { loginWithBasicAuth(); - // createDataSource(); + createDataSource(); cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); From 7c9d8adfc0187e7a7d4844aaeba244aa9f266182 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 15:13:46 -0400 Subject: [PATCH 08/27] Fix login issues Signed-off-by: Derek Ho --- ...ress-test-multidatasources-enabled-e2e.yml | 2 +- .../multi_datasources_enabled.spec.js | 6 ++--- test/cypress/support/commands.js | 26 ++++++++++++------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml index e02c260c8..3cdc72735 100644 --- a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml +++ b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml @@ -117,4 +117,4 @@ jobs: uses: ./.github/actions/run-cypress-tests with: dashboards_config_file: opensearch_dashboards_multidatasources.yml - yarn_command: 'yarn cypress:run --browser chrome --headless --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' + yarn_command: 'yarn cypress:run --browser chrome --headless --env BYPASS_LOGIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index f7d345b63..427da4682 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -13,8 +13,6 @@ * permissions and limitations under the License. */ -import { loginWithBasicAuth } from '../../support/commands'; - const createDataSource = () => { cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources/create'); cy.get('[data-test-subj="createDataSourceFormTitleField"]').type('9202'); @@ -28,7 +26,9 @@ const createDataSource = () => { describe('Multi-datasources enabled', () => { it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { - loginWithBasicAuth(); + localStorage.setItem('opendistro::security::tenant::saved', '""'); + localStorage.setItem('home:newThemeModal:show', 'false'); + createDataSource(); cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 818933049..3c7d4f68a 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -91,16 +91,22 @@ Cypress.Commands.add('loginWithSamlMultiauth', () => { cy.get('button[id=btn-sign-in]').should('be.visible').click(); }); -export const loginWithBasicAuth = () => { - cy.visit('http://localhost:5601', { - failOnStatusCode: false, - }); - cy.get('[data-test-subj="user-name"]').type('admin'); - cy.get('[data-test-subj="password"]').type('myStrongPassword123!'); - cy.get('[data-test-subj="submit"]').click(); - localStorage.setItem('opendistro::security::tenant::saved', '""'); - localStorage.setItem('home:newThemeModal:show', 'false'); -}; +Cypress.Commands.overwrite('visit', (orig, url, options) => { + if (Cypress.env('BYPASS_LOGIN')) { + let newOptions = options; + if (options) { + newOptions.auth = ADMIN_AUTH; + } else { + newOptions = { + auth: ADMIN_AUTH, + }; + } + + orig(url, newOptions); + } else { + orig(url, options); + } +}); Cypress.Commands.add('shortenUrl', (data, tenant) => { cy.request({ From dbab8c760caf6ed5c0ae4c904c03fc6e9c549c4b Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 15:25:12 -0400 Subject: [PATCH 09/27] Fix linting Signed-off-by: Derek Ho --- .../workflows/cypress-test-multidatasources-disabled-e2e.yml | 2 +- .../e2e/multi-datasources/multi_datasources_disabled.spec.js | 5 ++--- .../e2e/multi-datasources/multi_datasources_enabled.spec.js | 3 --- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml index 8079a2410..a85316586 100644 --- a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml +++ b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml @@ -46,4 +46,4 @@ jobs: uses: ./.github/actions/run-cypress-tests with: dashboards_config_file: opensearch_dashboards_multidatasources.yml - yarn_command: 'yarn cypress:run --browser chrome --headless --spec "test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js"' + yarn_command: 'yarn cypress:run --browser chrome --headless --env BYPASS_LOGIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js"' diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js index ac20b56cd..8cc4495b9 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js @@ -13,11 +13,10 @@ * permissions and limitations under the License. */ -import { loginWithBasicAuth } from '../../support/commands'; - describe('Multi-datasources enabled', () => { it('Sanity checks the cluster selector is not visible when multi datasources is disabled', () => { - loginWithBasicAuth(); + localStorage.setItem('opendistro::security::tenant::saved', '""'); + localStorage.setItem('home:newThemeModal:show', 'false'); cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted', { failOnStatusCode: false, diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index 427da4682..f2eff1faa 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -26,9 +26,6 @@ const createDataSource = () => { describe('Multi-datasources enabled', () => { it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { - localStorage.setItem('opendistro::security::tenant::saved', '""'); - localStorage.setItem('home:newThemeModal:show', 'false'); - createDataSource(); cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); From 4bf79b7580bebb38bfb4a73bcf259a128c5aa054 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 15:50:24 -0400 Subject: [PATCH 10/27] Fix test Signed-off-by: Derek Ho --- .../e2e/multi-datasources/multi_datasources_enabled.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index f2eff1faa..a0a515174 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -26,6 +26,8 @@ const createDataSource = () => { describe('Multi-datasources enabled', () => { it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { + localStorage.setItem('opendistro::security::tenant::saved', '""'); + localStorage.setItem('home:newThemeModal:show', 'false'); createDataSource(); cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); From 32e26184d990db9f3f052d7a475a84730877d423 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 14 Mar 2024 16:34:24 -0400 Subject: [PATCH 11/27] Enhancement to show datasource in toast Signed-off-by: Derek Ho --- .../apps/configuration/panels/get-started.tsx | 32 +++++++++++++++---- .../__snapshots__/get-started.test.tsx.snap | 2 ++ .../panels/test/get-started.test.tsx | 12 ++++++- public/apps/configuration/top-nav-menu.tsx | 6 ++-- public/types.ts | 7 +++- .../multi_datasources_enabled.spec.js | 2 +- 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/public/apps/configuration/panels/get-started.tsx b/public/apps/configuration/panels/get-started.tsx index e29581c59..e4bfc637e 100644 --- a/public/apps/configuration/panels/get-started.tsx +++ b/public/apps/configuration/panels/get-started.tsx @@ -37,6 +37,7 @@ import { ExternalLink, ExternalLinkButton } from '../utils/display-utils'; import { httpDelete } from '../utils/request-utils'; import { createSuccessToast, createUnknownErrorToast, useToastState } from '../utils/toast-utils'; import { SecurityPluginTopNavMenu } from '../top-nav-menu'; +import { Cluster } from '../../../types'; const addBackendStep = { title: 'Add backends', @@ -159,8 +160,16 @@ const setOfSteps = [ }, ]; +export function GetClusterDescription(dataSourceEnabled: boolean, cluster: Cluster) { + if (dataSourceEnabled) { + return `for ${cluster.label || 'Local cluster'}`; + } + return ''; +} + export function GetStarted(props: AppDependencies) { - const [datasourceId, setDatasourceId] = useState(''); + const dataSourceEnabled = !!props.securityPluginStartDeps.dataSource?.dataSourceEnabled; + const [dataSource, setDataSource] = useState({ id: '', label: '' }); let steps; if (props.config.ui.backend_configurable) { @@ -176,7 +185,7 @@ export function GetStarted(props: AppDependencies) { @@ -245,17 +254,28 @@ export function GetStarted(props: AppDependencies) { onClick={async () => { try { await httpDelete(props.coreStart.http, API_ENDPOINT_CACHE, { - dataSourceId: datasourceId, + dataSourceId: dataSource.id, }); addToast( createSuccessToast( 'cache-flush-success', - 'Cache purge successful', - 'Cache purge successful' + `Cache purge successful ${GetClusterDescription( + dataSourceEnabled, + dataSource + )}`, + `Cache purge successful ${GetClusterDescription( + dataSourceEnabled, + dataSource + )}` ) ); } catch (err) { - addToast(createUnknownErrorToast('cache-flush-failed', 'purge cache')); + addToast( + createUnknownErrorToast( + 'cache-flush-failed', + `purge cache ${GetClusterDescription(dataSourceEnabled, dataSource)}` + ) + ); } }} > diff --git a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap index f56cadecd..5cfb9bba4 100644 --- a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap +++ b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap @@ -21,6 +21,7 @@ exports[`Get started (landing page) renders when backend configuration is disabl dataSourcePickerReadOnly={false} navigation={Object {}} params={Object {}} + securityPluginStartDeps={Object {}} setDatasourceId={[Function]} /> @@ -292,6 +293,7 @@ exports[`Get started (landing page) renders when backend configuration is enable dataSourcePickerReadOnly={false} navigation={Object {}} params={Object {}} + securityPluginStartDeps={Object {}} setDatasourceId={[Function]} /> diff --git a/public/apps/configuration/panels/test/get-started.test.tsx b/public/apps/configuration/panels/test/get-started.test.tsx index fdd09500a..e8a0aee8c 100644 --- a/public/apps/configuration/panels/test/get-started.test.tsx +++ b/public/apps/configuration/panels/test/get-started.test.tsx @@ -19,7 +19,7 @@ import { EuiSteps } from '@elastic/eui'; import { Action } from '../../types'; import { ResourceType } from '../../../../../common'; import { buildHashUrl } from '../../utils/url-builder'; -import { GetStarted } from '../get-started'; +import { GetClusterDescription, GetStarted } from '../get-started'; import * as ToastUtils from '../../utils/toast-utils'; // Import all functions from toast-utils import * as RequestUtils from '../../utils/request-utils'; // Import all functions from request-utils @@ -50,6 +50,7 @@ describe('Get started (landing page)', () => { navigation={{} as any} params={{} as any} config={config as any} + securityPluginStartDeps={{}} /> ); expect(component).toMatchSnapshot(); @@ -67,6 +68,7 @@ describe('Get started (landing page)', () => { navigation={{} as any} params={{} as any} config={config1 as any} + securityPluginStartDeps={{}} /> ); expect(component).toMatchSnapshot(); @@ -81,6 +83,7 @@ describe('Get started (landing page)', () => { navigation={{} as any} params={{} as any} config={config as any} + securityPluginStartDeps={{}} /> ); jest.clearAllMocks(); @@ -143,6 +146,7 @@ describe('Get started (landing page)', () => { navigation={{} as any} params={{} as any} config={config as any} + securityPluginStartDeps={{}} /> ); jest.clearAllMocks(); @@ -170,5 +174,11 @@ describe('Get started (landing page)', () => { await button.props().onClick(); // Simulate button click expect(ToastUtils.createSuccessToast).toHaveBeenCalledTimes(1); }); + + it('Tests the GetClusterDescription helper function', () => { + expect(GetClusterDescription(false, { id: 'blah', label: 'blah' })).toBe(''); + expect(GetClusterDescription(true, { id: '', label: '' })).toBe('for Local cluster'); + expect(GetClusterDescription(true, { id: 'test', label: 'test' })).toBe('for test'); + }); }); }); diff --git a/public/apps/configuration/top-nav-menu.tsx b/public/apps/configuration/top-nav-menu.tsx index c2e95dab6..20c171245 100644 --- a/public/apps/configuration/top-nav-menu.tsx +++ b/public/apps/configuration/top-nav-menu.tsx @@ -19,17 +19,17 @@ import { NavigationPublicPluginStart } from 'src/plugins/navigation/public/types import { ClientConfigType } from '../../types'; import { PLUGIN_NAME } from '../../../common'; import { AppDependencies } from '../types'; +import { Cluster } from '../../types'; export interface TopNavMenuProps extends AppDependencies { dataSourcePickerReadOnly: boolean; - setDatasourceId: React.Dispatch>; + setDatasourceId: React.Dispatch>; } export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { const { coreStart, securityPluginStartDeps, - dataSourcePickerReadOnly, setHeaderActionMenu, dataSourceManagement, setDatasourceId, @@ -44,7 +44,7 @@ export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { savedObjects={coreStart.savedObjects.client} setMenuMountPoint={setHeaderActionMenu} notifications={coreStart.notifications} - dataSourceCallBackFunc={(datasource) => setDatasourceId(datasource.id)} + dataSourceCallBackFunc={(datasource) => setDatasourceId(datasource)} hideLocalCluster={false} fullWidth={false} /> diff --git a/public/types.ts b/public/types.ts index f9dd312df..96e587354 100644 --- a/public/types.ts +++ b/public/types.ts @@ -33,10 +33,15 @@ export interface SecurityPluginSetupDependencies { dataSourceManagement?: DataSourceManagementPluginSetup; } +export interface Cluster { + id: string; + label: string; +} + export interface SecurityPluginStartDependencies { navigation: NavigationPublicPluginStart; savedObjectsManagement: SavedObjectsManagementPluginStart; - dataSource: DataSourcePluginStart; + dataSource?: DataSourcePluginStart; } export interface AuthInfo { diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index a0a515174..aa7e3ced9 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -35,6 +35,6 @@ describe('Multi-datasources enabled', () => { cy.get('[data-test-subj="dataSourceSelectableContextMenuHeaderLink"]').click(); cy.contains('li.euiSelectableListItem', '9202').click(); cy.get('[data-test-subj="purge-cache"]').click(); - cy.get('.euiToastHeader__title').should('contain', 'successful'); + cy.get('.euiToastHeader__title').should('contain', 'successful for 9202'); }); }); From f19f011976afb50d39b563b5572bb4232b2fca04 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 15 Mar 2024 13:40:23 -0400 Subject: [PATCH 12/27] Refactor Signed-off-by: Derek Ho --- .../apps/configuration/configuration-app.tsx | 2 - .../apps/configuration/panels/get-started.tsx | 8 +-- .../panels/test/get-started.test.tsx | 51 +++++++++++-- public/apps/configuration/top-nav-menu.tsx | 3 +- public/apps/types.ts | 1 - public/plugin.ts | 1 - server/routes/index.ts | 72 ++++++++++++------- .../multi_datasources_enabled.spec.js | 20 +++++- test/cypress/support/commands.js | 16 +---- 9 files changed, 119 insertions(+), 55 deletions(-) diff --git a/public/apps/configuration/configuration-app.tsx b/public/apps/configuration/configuration-app.tsx index 16627c9cd..d7c395742 100644 --- a/public/apps/configuration/configuration-app.tsx +++ b/public/apps/configuration/configuration-app.tsx @@ -28,7 +28,6 @@ export function renderApp( securityPluginStartDeps: SecurityPluginStartDependencies, params: AppMountParameters, config: ClientConfigType, - setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'], dataSourceManagement?: DataSourceManagementPluginSetup ) { const deps = { @@ -36,7 +35,6 @@ export function renderApp( securityPluginStartDeps, params, config, - setHeaderActionMenu, dataSourceManagement, }; ReactDOM.render( diff --git a/public/apps/configuration/panels/get-started.tsx b/public/apps/configuration/panels/get-started.tsx index e4bfc637e..40ad06331 100644 --- a/public/apps/configuration/panels/get-started.tsx +++ b/public/apps/configuration/panels/get-started.tsx @@ -160,7 +160,7 @@ const setOfSteps = [ }, ]; -export function GetClusterDescription(dataSourceEnabled: boolean, cluster: Cluster) { +export function getClusterInfoIfEnabled(dataSourceEnabled: boolean, cluster: Cluster) { if (dataSourceEnabled) { return `for ${cluster.label || 'Local cluster'}`; } @@ -259,11 +259,11 @@ export function GetStarted(props: AppDependencies) { addToast( createSuccessToast( 'cache-flush-success', - `Cache purge successful ${GetClusterDescription( + `Cache purge successful ${getClusterInfoIfEnabled( dataSourceEnabled, dataSource )}`, - `Cache purge successful ${GetClusterDescription( + `Cache purge successful ${getClusterInfoIfEnabled( dataSourceEnabled, dataSource )}` @@ -273,7 +273,7 @@ export function GetStarted(props: AppDependencies) { addToast( createUnknownErrorToast( 'cache-flush-failed', - `purge cache ${GetClusterDescription(dataSourceEnabled, dataSource)}` + `purge cache ${getClusterInfoIfEnabled(dataSourceEnabled, dataSource)}` ) ); } diff --git a/public/apps/configuration/panels/test/get-started.test.tsx b/public/apps/configuration/panels/test/get-started.test.tsx index e8a0aee8c..b04ad3119 100644 --- a/public/apps/configuration/panels/test/get-started.test.tsx +++ b/public/apps/configuration/panels/test/get-started.test.tsx @@ -19,7 +19,7 @@ import { EuiSteps } from '@elastic/eui'; import { Action } from '../../types'; import { ResourceType } from '../../../../../common'; import { buildHashUrl } from '../../utils/url-builder'; -import { GetClusterDescription, GetStarted } from '../get-started'; +import { GetStarted, getClusterInfoIfEnabled } from '../get-started'; import * as ToastUtils from '../../utils/toast-utils'; // Import all functions from toast-utils import * as RequestUtils from '../../utils/request-utils'; // Import all functions from request-utils @@ -176,9 +176,52 @@ describe('Get started (landing page)', () => { }); it('Tests the GetClusterDescription helper function', () => { - expect(GetClusterDescription(false, { id: 'blah', label: 'blah' })).toBe(''); - expect(GetClusterDescription(true, { id: '', label: '' })).toBe('for Local cluster'); - expect(GetClusterDescription(true, { id: 'test', label: 'test' })).toBe('for test'); + expect(getClusterInfoIfEnabled(false, { id: 'blah', label: 'blah' })).toBe(''); + expect(getClusterInfoIfEnabled(true, { id: '', label: '' })).toBe('for Local cluster'); + expect(getClusterInfoIfEnabled(true, { id: 'test', label: 'test' })).toBe('for test'); }); }); + + describe('Tests the cluster selector is hooked up correctly', () => { + describe('Tenant list', () => { + const setState = jest.fn(); + const mockCoreStart = { + http: 1, + chrome: { + setBreadcrumbs() { + return 1; + }, + }, + }; + const config = { + multitenancy: { + enabled: true, + tenants: { + enable_private: true, + }, + }, + }; + + beforeEach(() => { + jest.spyOn(React, 'useState').mockImplementation((initialValue) => [initialValue, setState]); + }); + + + it('renders when multitenancy is disabled in the opensearch_dashboards.yml', (done) => { + const component = shallow( + ); + process.nextTick(() => { + expect(setState).toHaveBeenCalledWith(true); + done(); + }); + }); + + }); + }) }); diff --git a/public/apps/configuration/top-nav-menu.tsx b/public/apps/configuration/top-nav-menu.tsx index 20c171245..317cdbcf2 100644 --- a/public/apps/configuration/top-nav-menu.tsx +++ b/public/apps/configuration/top-nav-menu.tsx @@ -30,10 +30,11 @@ export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { const { coreStart, securityPluginStartDeps, - setHeaderActionMenu, + params, dataSourceManagement, setDatasourceId, } = props; + const { setHeaderActionMenu } = params; const DataSourceMenu = dataSourceManagement?.ui.DataSourceMenu; const dataSourceEnabled = !!securityPluginStartDeps.dataSource?.dataSourceEnabled; diff --git a/public/apps/types.ts b/public/apps/types.ts index d92e63842..86ef08672 100644 --- a/public/apps/types.ts +++ b/public/apps/types.ts @@ -23,7 +23,6 @@ export interface AppDependencies { params: AppMountParameters; config: ClientConfigType; dashboardsInfo: DashboardsInfo; - setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; dataSourceManagement: DataSourceManagementPluginSetup; } diff --git a/public/plugin.ts b/public/plugin.ts index a8b4fea5e..ca9798a94 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -117,7 +117,6 @@ export class SecurityPlugin depsStart as SecurityPluginStartDependencies, params, config, - params.setHeaderActionMenu, deps.dataSourceManagement ); }, diff --git a/server/routes/index.ts b/server/routes/index.ts index 017cf818d..22da821d3 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -19,6 +19,8 @@ import { ResponseError, IOpenSearchDashboardsResponse, OpenSearchDashboardsResponseFactory, + RequestHandlerContext, + OpenSearchDashboardsRequest, } from 'opensearch-dashboards/server'; import { API_PREFIX, CONFIGURATION_API_PREFIX, isValidResourceName } from '../../common'; import { ResourceType } from '../../common'; @@ -752,33 +754,13 @@ export function defineRoutes(router: IRouter, dataSourceEnabled: boolean) { }, }, async (context, request, response) => { - if (!dataSourceEnabled || !request.body?.dataSourceId) { - const client = context.security_plugin.esClient.asScoped(request); - let esResponse; - try { - esResponse = await client.callAsCurrentUser('opensearch_security.clearCache'); - return response.ok({ - body: { - message: esResponse.message, - }, - }); - } catch (error) { - return errorResponse(response, error); - } - } else { - const client = context.dataSource.opensearch.legacy.getClient(request.body?.dataSourceId); - let esResponse; - try { - esResponse = await client.callAPI('opensearch_security.clearCache', {}); - return response.ok({ - body: { - message: esResponse.message, - }, - }); - } catch (error) { - return errorResponse(response, error); - } - } + return wrapRouteWithDataSource( + dataSourceEnabled, + context, + request, + response, + 'opensearch_security.clearCache' + ); } ); @@ -902,6 +884,42 @@ export function defineRoutes(router: IRouter, dataSourceEnabled: boolean) { ); } +const wrapRouteWithDataSource = async ( + dataSourceEnabled: boolean, + context: RequestHandlerContext, + request: OpenSearchDashboardsRequest, + response: OpenSearchDashboardsResponseFactory, + endpoint: string +) => { + if (!dataSourceEnabled || !request.body?.dataSourceId) { + const client = context.security_plugin.esClient.asScoped(request); + let esResponse; + try { + esResponse = await client.callAsCurrentUser(endpoint); + return response.ok({ + body: { + message: esResponse.message, + }, + }); + } catch (error) { + return errorResponse(response, error); + } + } else { + const client = context.dataSource.opensearch.legacy.getClient(request.body?.dataSourceId); + let esResponse; + try { + esResponse = await client.callAPI(endpoint, {}); + return response.ok({ + body: { + message: esResponse.message, + }, + }); + } catch (error) { + return errorResponse(response, error); + } + } +}; + function parseEsErrorResponse(error: any) { if (error.response) { try { diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index aa7e3ced9..ac33d31b4 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -24,14 +24,30 @@ const createDataSource = () => { cy.get('[data-test-subj="createDataSourceButton"]').click(); }; +const deleteAllDataSources = () => { + cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources'); + cy.get('[data-test-subj="checkboxSelectAll"]').click(); + cy.get('[data-test-subj="deleteDataSourceConnections"]').click(); + cy.get('[data-test-subj="confirmModalConfirmButton"]').click(); +}; + describe('Multi-datasources enabled', () => { - it('Sanity checks the cluster selector is visible when multi datasources is enabled', () => { + before(() => { localStorage.setItem('opendistro::security::tenant::saved', '""'); localStorage.setItem('home:newThemeModal:show', 'false'); createDataSource(); + }); - cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); + after(() => { + deleteAllDataSources(); + }); + it('Checks Get Started Tab', () => { + cy.visit('http://localhost:5601/app/security-dashboards-plugin#/getstarted'); + // Local cluster purge cache + cy.get('[data-test-subj="purge-cache"]').click(); + cy.get('.euiToastHeader__title').should('contain', 'successful for Local cluster'); + // Remote cluster purge cache cy.get('[data-test-subj="dataSourceSelectableContextMenuHeaderLink"]').click(); cy.contains('li.euiSelectableListItem', '9202').click(); cy.get('[data-test-subj="purge-cache"]').click(); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 3c7d4f68a..aee2a041a 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -91,21 +91,11 @@ Cypress.Commands.add('loginWithSamlMultiauth', () => { cy.get('button[id=btn-sign-in]').should('be.visible').click(); }); -Cypress.Commands.overwrite('visit', (orig, url, options) => { +Cypress.Commands.overwrite('visit', (orig, url, options = {}) => { if (Cypress.env('BYPASS_LOGIN')) { - let newOptions = options; - if (options) { - newOptions.auth = ADMIN_AUTH; - } else { - newOptions = { - auth: ADMIN_AUTH, - }; - } - - orig(url, newOptions); - } else { - orig(url, options); + options.auth = ADMIN_AUTH; } + orig(url, options); }); Cypress.Commands.add('shortenUrl', (data, tenant) => { From d3ab2512da26a190673cc6635d91aaec157c646a Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 15 Mar 2024 14:52:31 -0400 Subject: [PATCH 13/27] Lint Signed-off-by: Derek Ho --- .../panels/test/get-started.test.tsx | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/public/apps/configuration/panels/test/get-started.test.tsx b/public/apps/configuration/panels/test/get-started.test.tsx index b04ad3119..9bb390516 100644 --- a/public/apps/configuration/panels/test/get-started.test.tsx +++ b/public/apps/configuration/panels/test/get-started.test.tsx @@ -181,47 +181,4 @@ describe('Get started (landing page)', () => { expect(getClusterInfoIfEnabled(true, { id: 'test', label: 'test' })).toBe('for test'); }); }); - - describe('Tests the cluster selector is hooked up correctly', () => { - describe('Tenant list', () => { - const setState = jest.fn(); - const mockCoreStart = { - http: 1, - chrome: { - setBreadcrumbs() { - return 1; - }, - }, - }; - const config = { - multitenancy: { - enabled: true, - tenants: { - enable_private: true, - }, - }, - }; - - beforeEach(() => { - jest.spyOn(React, 'useState').mockImplementation((initialValue) => [initialValue, setState]); - }); - - - it('renders when multitenancy is disabled in the opensearch_dashboards.yml', (done) => { - const component = shallow( - ); - process.nextTick(() => { - expect(setState).toHaveBeenCalledWith(true); - done(); - }); - }); - - }); - }) }); From 9c97f92fb5959a7a453511fd8b2a1a52f8b20e85 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Fri, 15 Mar 2024 15:06:47 -0400 Subject: [PATCH 14/27] Fix test Signed-off-by: Derek Ho --- public/apps/configuration/test/top-nav-menu.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/apps/configuration/test/top-nav-menu.test.tsx b/public/apps/configuration/test/top-nav-menu.test.tsx index 91e482ead..240b224b0 100644 --- a/public/apps/configuration/test/top-nav-menu.test.tsx +++ b/public/apps/configuration/test/top-nav-menu.test.tsx @@ -50,7 +50,7 @@ describe('SecurityPluginTopNavMenu', () => { securityPluginStartDeps={securityPluginStartDepsMock} dataSourcePickerReadOnly={false} dataSourceManagement={dataSourceManagementMock} - setHeaderActionMenu={() => {}} + params={{}} /> ); @@ -72,6 +72,7 @@ describe('SecurityPluginTopNavMenu', () => { dataSourcePickerReadOnly={false} dataSourceManagement={dataSourceManagementMock} setHeaderActionMenu={() => {}} + params={{}} /> ); From 88fa11278e4b6ef938390e9c25ed2de02665cc33 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 10:49:45 -0400 Subject: [PATCH 15/27] Add support for testing the framework end to end Signed-off-by: Derek Ho --- .github/workflows/integration-test.yml | 56 ++++++++++ .../security_entity_api.test.ts | 101 ++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 40dcdfecc..0b5713b08 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -59,6 +59,62 @@ jobs: plugin-name: ${{ env.PLUGIN_NAME }} plugin-version: ${{ env.PLUGIN_VERSION }} + - name: Create remote OpenSearch Config + if: ${{ runner.os == 'Linux' }} + run: | + cat << 'EOT' > remote_opensearch.yml + http.port: 9202 + plugins.security.ssl.transport.pemcert_filepath: esnode.pem + plugins.security.ssl.transport.pemkey_filepath: esnode-key.pem + plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem + plugins.security.ssl.transport.enforce_hostname_verification: false + plugins.security.ssl.http.pemcert_filepath: esnode.pem + plugins.security.ssl.http.pemkey_filepath: esnode-key.pem + plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem + plugins.security.allow_unsafe_democertificates: true + plugins.security.allow_default_init_securityindex: true + plugins.security.authcz.admin_dn: + - 'CN=A,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA' + plugins.security.nodes_dn: + - 'CN=node1.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA' + - 'CN=node2.dns.a-record,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA' + plugins.security.audit.type: internal_opensearch + plugins.security.enable_snapshot_restore_privilege: true + plugins.security.check_snapshot_restore_write_privileges: true + # TODO: change this back to true/just append to the created opensearch.yml the new port + # after the self-signed certs issue is fixed + plugins.security.ssl.http.enabled: false + plugins.security.restapi.roles_enabled: [all_access, security_rest_api_access] + plugins.security.system_indices.enabled: true + plugins.security.system_indices.indices: [.plugins-ml-config, .plugins-ml-connector, + .plugins-ml-model-group, .plugins-ml-model, .plugins-ml-task, .plugins-ml-conversation-meta, + .plugins-ml-conversation-interactions, .plugins-ml-memory-meta, .plugins-ml-memory-message, + .opendistro-alerting-config, .opendistro-alerting-alert*, .opendistro-anomaly-results*, + .opendistro-anomaly-detector*, .opendistro-anomaly-checkpoints, .opendistro-anomaly-detection-state, + .opendistro-reports-*, .opensearch-notifications-*, .opensearch-notebooks, .opensearch-observability, + .ql-datasources, .opendistro-asynchronous-search-response*, .replication-metadata-store, + .opensearch-knn-models, .geospatial-ip2geo-data*, .plugins-flow-framework-config, + .plugins-flow-framework-templates, .plugins-flow-framework-state] + node.max_local_storage_nodes: 3 + EOT + + - name: Run Opensearch with A Single Plugin + uses: derek-ho/start-opensearch@9202 + with: + opensearch-version: ${{ env.OPENSEARCH_VERSION }} + plugins: "file:$(pwd)/opensearch-security.zip" + security-enabled: true + admin-password: ${{ env.OPENSEARCH_INITIAL_ADMIN_PASSWORD }} + security_config_file: ${{ inputs.security_config_file }} + opensearch_yml_file: remote_opensearch.yml + opensearch_port: 9202 + + - name: Check OpenSearch is running + # Verify that the server is operational + run: | + curl http://localhost:9202/_cat/plugins -v -u admin:myStrongPassword123! + shell: bash + - name: Run Opensearch with security uses: derek-ho/start-opensearch@v2 with: diff --git a/test/jest_integration/security_entity_api.test.ts b/test/jest_integration/security_entity_api.test.ts index dc84e3303..26431a2cc 100644 --- a/test/jest_integration/security_entity_api.test.ts +++ b/test/jest_integration/security_entity_api.test.ts @@ -355,6 +355,13 @@ describe('start OpenSearch Dashboards server', () => { .send({ dataSourceId: '' }); expect(deleteCacheResponse.status).toEqual(200); + // Multi datasources not enabled so dataSourceId is not read + const deleteCacheResponseMultiDataSource = await osdTestServer.request + .delete(root, '/api/v1/configuration/cache') + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ dataSourceId: 'Derek Datasource' }); + expect(deleteCacheResponseMultiDataSource.status).toEqual(200); + const adminAuthCookie = await getAuthCookie(root, ADMIN_USER, ADMIN_PASSWORD); const deleteCacheWithCookieResponse = await osdTestServer.request .delete(root, '/api/v1/configuration/cache') @@ -362,6 +369,13 @@ describe('start OpenSearch Dashboards server', () => { .set('Cookie', adminAuthCookie) .send({ dataSourceId: '' }); expect(deleteCacheWithCookieResponse.status).toEqual(200); + + // Multi datasources not enabled so dataSourceId is not read + const deleteCacheResponseMultiDataSourceCookie = await osdTestServer.request + .delete(root, '/api/v1/configuration/cache') + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ dataSourceId: 'Derek Datasource' }); + expect(deleteCacheResponseMultiDataSourceCookie.status).toEqual(200); }); it('restapiinfo', async () => { @@ -408,3 +422,90 @@ describe('start OpenSearch Dashboards server', () => { expect(response.status).toEqual(200); }); }); + +describe('start OpenSearch Dashboards server multi datasources enabled', () => { + let root: Root; + + beforeAll(async () => { + root = osdTestServer.createRootWithSettings( + { + plugins: { + scanDirs: [resolve(__dirname, '../..')], + }, + data_source: { enabled: true }, + opensearch: { + hosts: ['https://localhost:9200'], + ignoreVersionMismatch: true, + ssl: { verificationMode: 'none' }, + username: OPENSEARCH_DASHBOARDS_SERVER_USER, + password: OPENSEARCH_DASHBOARDS_SERVER_PASSWORD, + }, + opensearch_security: { + multitenancy: { enabled: true, tenants: { preferred: ['Private', 'Global'] } }, + }, + }, + { + // to make ignoreVersionMismatch setting work + // can be removed when we have corresponding ES version + dev: true, + } + ); + + console.log('Starting OpenSearchDashboards server..'); + await root.setup(); + await root.start(); + console.log('Started OpenSearchDashboards server'); + }); + + afterAll(async () => { + // shutdown OpenSearchDashboards server + await root.shutdown(); + }); + + it('delete cache', async () => { + const deleteCacheResponseWrongDataSource = await osdTestServer.request + .delete(root, '/api/v1/configuration/cache') + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ dataSourceId: 'test' }); + + // Calling clear cache on a datasource that does not exist + expect(deleteCacheResponseWrongDataSource.status).not.toEqual(200); + expect(deleteCacheResponseWrongDataSource.text).toContain( + 'Data Source Error: Saved object [data-source/test] not found' + ); + + const deleteCacheResponseEmptyDataSource = await osdTestServer.request + .delete(root, '/api/v1/configuration/cache') + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ dataSourceId: '' }); + + // Calling clear cache on an empty datasource calls local cluster + expect(deleteCacheResponseEmptyDataSource.status).toEqual(200); + + const createDataSource = await osdTestServer.request + .post(root, '/api/saved_objects/data-source') + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ + attributes: { + title: 'test', + description: '', + endpoint: 'http://localhost:9202', + auth: { + type: 'username_password', + credentials: { + username: 'admin', + password: 'myStrongPassword123!', + }, + }, + }, + }); + + const deleteCacheResponseRemoteDataSource = await osdTestServer.request + .delete(root, '/api/v1/configuration/cache') + .set(AUTHORIZATION_HEADER_NAME, ADMIN_CREDENTIALS) + .send({ dataSourceId: createDataSource.body.id }); + + // Calling clear cache on an empty datasource calls local cluster + expect(deleteCacheResponseRemoteDataSource.status).toEqual(200); + }); +}); From 1f10316bcf430a5564ed6456f135be4cd9eb8787 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 11:08:51 -0400 Subject: [PATCH 16/27] Fix creds Signed-off-by: Derek Ho --- test/jest_integration/security_entity_api.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jest_integration/security_entity_api.test.ts b/test/jest_integration/security_entity_api.test.ts index 26431a2cc..e179cd136 100644 --- a/test/jest_integration/security_entity_api.test.ts +++ b/test/jest_integration/security_entity_api.test.ts @@ -494,7 +494,7 @@ describe('start OpenSearch Dashboards server multi datasources enabled', () => { type: 'username_password', credentials: { username: 'admin', - password: 'myStrongPassword123!', + password: 'admin', }, }, }, From 4b9f8f4d4fffec629caf11af3537b8b240c85efd Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 12:09:19 -0400 Subject: [PATCH 17/27] Try focus to remove flakiness Signed-off-by: Derek Ho --- .../multi_datasources_enabled.spec.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index ac33d31b4..cccf39bc4 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -15,10 +15,14 @@ const createDataSource = () => { cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources/create'); - cy.get('[data-test-subj="createDataSourceFormTitleField"]').type('9202'); - cy.get('[data-test-subj="createDataSourceFormEndpointField"]').type('http://localhost:9202'); - cy.get('[data-test-subj="createDataSourceFormUsernameField"]').type('admin'); - cy.get('[data-test-subj="createDataSourceFormPasswordField"]').type('myStrongPassword123!'); + cy.get('[data-test-subj="createDataSourceFormTitleField"]').focus().type('9202'); + cy.get('[data-test-subj="createDataSourceFormEndpointField"]') + .focus() + .type('http://localhost:9202'); + cy.get('[data-test-subj="createDataSourceFormUsernameField"]').focus().type('admin'); + cy.get('[data-test-subj="createDataSourceFormPasswordField"]') + .focus() + .type('myStrongPassword123!'); cy.get('[data-test-subj="createDataSourceTestConnectionButton"]').click(); cy.get('.euiToastHeader__title').should('contain', 'successful'); cy.get('[data-test-subj="createDataSourceButton"]').click(); From 27c2c043a7a3bafec85c19c8140f60579fc6c4dc Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 15:52:13 -0400 Subject: [PATCH 18/27] Fix files Signed-off-by: Derek Ho --- .../cypress-test-multidatasources-disabled-e2e.yml | 2 +- .../cypress-test-multidatasources-enabled-e2e.yml | 2 +- public/apps/configuration/configuration-app.tsx | 4 ++-- public/apps/configuration/panels/get-started.tsx | 2 +- .../test/__snapshots__/get-started.test.tsx.snap | 6 ++---- .../configuration/panels/test/get-started.test.tsx | 12 ++++-------- public/apps/configuration/test/top-nav-menu.test.tsx | 10 +++------- public/apps/configuration/top-nav-menu.tsx | 10 ++-------- public/apps/types.ts | 2 +- .../multi_datasources_enabled.spec.js | 3 +++ test/cypress/support/commands.js | 2 +- 11 files changed, 21 insertions(+), 34 deletions(-) diff --git a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml index a85316586..f20478ddb 100644 --- a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml +++ b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml @@ -46,4 +46,4 @@ jobs: uses: ./.github/actions/run-cypress-tests with: dashboards_config_file: opensearch_dashboards_multidatasources.yml - yarn_command: 'yarn cypress:run --browser chrome --headless --env BYPASS_LOGIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js"' + yarn_command: 'yarn cypress:run --browser chrome --headless --env LOGIN_AS_ADMIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_disabled.spec.js"' diff --git a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml index 3cdc72735..2e6dd8ce6 100644 --- a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml +++ b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml @@ -117,4 +117,4 @@ jobs: uses: ./.github/actions/run-cypress-tests with: dashboards_config_file: opensearch_dashboards_multidatasources.yml - yarn_command: 'yarn cypress:run --browser chrome --headless --env BYPASS_LOGIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' + yarn_command: 'yarn cypress:run --browser chrome --headless --env LOGIN_AS_ADMIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' diff --git a/public/apps/configuration/configuration-app.tsx b/public/apps/configuration/configuration-app.tsx index d7c395742..1f341f781 100644 --- a/public/apps/configuration/configuration-app.tsx +++ b/public/apps/configuration/configuration-app.tsx @@ -25,14 +25,14 @@ import { DataSourceManagementPluginSetup } from '../../../../../src/plugins/data export function renderApp( coreStart: CoreStart, - securityPluginStartDeps: SecurityPluginStartDependencies, + depsStart: SecurityPluginStartDependencies, params: AppMountParameters, config: ClientConfigType, dataSourceManagement?: DataSourceManagementPluginSetup ) { const deps = { coreStart, - securityPluginStartDeps, + depsStart, params, config, dataSourceManagement, diff --git a/public/apps/configuration/panels/get-started.tsx b/public/apps/configuration/panels/get-started.tsx index 40ad06331..a8a082e22 100644 --- a/public/apps/configuration/panels/get-started.tsx +++ b/public/apps/configuration/panels/get-started.tsx @@ -168,7 +168,7 @@ export function getClusterInfoIfEnabled(dataSourceEnabled: boolean, cluster: Clu } export function GetStarted(props: AppDependencies) { - const dataSourceEnabled = !!props.securityPluginStartDeps.dataSource?.dataSourceEnabled; + const dataSourceEnabled = !!props.depsStart.dataSource?.dataSourceEnabled; const [dataSource, setDataSource] = useState({ id: '', label: '' }); let steps; diff --git a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap index 5cfb9bba4..81d2bfb1d 100644 --- a/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap +++ b/public/apps/configuration/panels/test/__snapshots__/get-started.test.tsx.snap @@ -19,9 +19,8 @@ exports[`Get started (landing page) renders when backend configuration is disabl } } dataSourcePickerReadOnly={false} - navigation={Object {}} + depsStart={Object {}} params={Object {}} - securityPluginStartDeps={Object {}} setDatasourceId={[Function]} /> @@ -291,9 +290,8 @@ exports[`Get started (landing page) renders when backend configuration is enable } } dataSourcePickerReadOnly={false} - navigation={Object {}} + depsStart={Object {}} params={Object {}} - securityPluginStartDeps={Object {}} setDatasourceId={[Function]} /> diff --git a/public/apps/configuration/panels/test/get-started.test.tsx b/public/apps/configuration/panels/test/get-started.test.tsx index 9bb390516..fe412276a 100644 --- a/public/apps/configuration/panels/test/get-started.test.tsx +++ b/public/apps/configuration/panels/test/get-started.test.tsx @@ -47,10 +47,9 @@ describe('Get started (landing page)', () => { const component = shallow( ); expect(component).toMatchSnapshot(); @@ -65,10 +64,9 @@ describe('Get started (landing page)', () => { const component = shallow( ); expect(component).toMatchSnapshot(); @@ -80,10 +78,9 @@ describe('Get started (landing page)', () => { wrapper = shallow( ); jest.clearAllMocks(); @@ -143,10 +140,9 @@ describe('Get started (landing page)', () => { wrapper = shallow( ); jest.clearAllMocks(); diff --git a/public/apps/configuration/test/top-nav-menu.test.tsx b/public/apps/configuration/test/top-nav-menu.test.tsx index 240b224b0..93fef3d80 100644 --- a/public/apps/configuration/test/top-nav-menu.test.tsx +++ b/public/apps/configuration/test/top-nav-menu.test.tsx @@ -14,12 +14,8 @@ */ import React from 'react'; -import { mount, render, shallow } from 'enzyme'; +import { render } from 'enzyme'; import { SecurityPluginTopNavMenu } from '../top-nav-menu'; -import { - DataSourceManagementPluginSetup, - DataSourceMenu, -} from '../../../../../../src/plugins/data_source_management/public'; describe('SecurityPluginTopNavMenu', () => { const coreStartMock = { @@ -47,7 +43,7 @@ describe('SecurityPluginTopNavMenu', () => { const wrapper = render( { const wrapper = render( {}} diff --git a/public/apps/configuration/top-nav-menu.tsx b/public/apps/configuration/top-nav-menu.tsx index 317cdbcf2..b36d46e6e 100644 --- a/public/apps/configuration/top-nav-menu.tsx +++ b/public/apps/configuration/top-nav-menu.tsx @@ -27,16 +27,10 @@ export interface TopNavMenuProps extends AppDependencies { } export const SecurityPluginTopNavMenu = (props: TopNavMenuProps) => { - const { - coreStart, - securityPluginStartDeps, - params, - dataSourceManagement, - setDatasourceId, - } = props; + const { coreStart, depsStart, params, dataSourceManagement, setDatasourceId } = props; const { setHeaderActionMenu } = params; const DataSourceMenu = dataSourceManagement?.ui.DataSourceMenu; - const dataSourceEnabled = !!securityPluginStartDeps.dataSource?.dataSourceEnabled; + const dataSourceEnabled = !!depsStart.dataSource?.dataSourceEnabled; return dataSourceEnabled ? ( { cy.get('[data-test-subj="createDataSourceTestConnectionButton"]').click(); cy.get('.euiToastHeader__title').should('contain', 'successful'); cy.get('[data-test-subj="createDataSourceButton"]').click(); + // Wait for dataSource to be created + cy.url().should('eq', 'http://localhost:5601/app/management/opensearch-dashboards/dataSources'); }; const deleteAllDataSources = () => { @@ -44,6 +46,7 @@ describe('Multi-datasources enabled', () => { after(() => { deleteAllDataSources(); + cy.clearLocalStorage(); }); it('Checks Get Started Tab', () => { diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index aee2a041a..efd021c47 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -92,7 +92,7 @@ Cypress.Commands.add('loginWithSamlMultiauth', () => { }); Cypress.Commands.overwrite('visit', (orig, url, options = {}) => { - if (Cypress.env('BYPASS_LOGIN')) { + if (Cypress.env('LOGIN_AS_ADMIN')) { options.auth = ADMIN_AUTH; } orig(url, options); From d4c92b1d4fbb308b48b7d3f7be90151c41765dae Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 16:15:49 -0400 Subject: [PATCH 19/27] Try fixes for tests Signed-off-by: Derek Ho --- .github/workflows/integration-test.yml | 1 - .../e2e/multi-datasources/multi_datasources_enabled.spec.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 0b5713b08..f47e017eb 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -60,7 +60,6 @@ jobs: plugin-version: ${{ env.PLUGIN_VERSION }} - name: Create remote OpenSearch Config - if: ${{ runner.os == 'Linux' }} run: | cat << 'EOT' > remote_opensearch.yml http.port: 9202 diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index 8cd91a725..b57574134 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -25,7 +25,7 @@ const createDataSource = () => { .type('myStrongPassword123!'); cy.get('[data-test-subj="createDataSourceTestConnectionButton"]').click(); cy.get('.euiToastHeader__title').should('contain', 'successful'); - cy.get('[data-test-subj="createDataSourceButton"]').click(); + cy.get('[data-test-subj="createDataSourceButton"]').click({ force: true }); // Wait for dataSource to be created cy.url().should('eq', 'http://localhost:5601/app/management/opensearch-dashboards/dataSources'); }; From d5522d0ea909fc257c98000991f7b0572e2570e9 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 16:19:07 -0400 Subject: [PATCH 20/27] Add shell Signed-off-by: Derek Ho --- .github/workflows/integration-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index f47e017eb..8948f14b0 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -96,6 +96,7 @@ jobs: .plugins-flow-framework-templates, .plugins-flow-framework-state] node.max_local_storage_nodes: 3 EOT + shell: bash - name: Run Opensearch with A Single Plugin uses: derek-ho/start-opensearch@9202 From 3f577d54d2f895ff63ebcfd87f55581a70d162ec Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 18:10:24 -0400 Subject: [PATCH 21/27] Try final cleanup Signed-off-by: Derek Ho --- .../multi_datasources_enabled.spec.js | 4 +++- test/cypress/support/commands.js | 15 +++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index b57574134..68655f71a 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -14,7 +14,9 @@ */ const createDataSource = () => { - cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources/create'); + cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources/create', { + failOnStatusCode: false, + }); cy.get('[data-test-subj="createDataSourceFormTitleField"]').focus().type('9202'); cy.get('[data-test-subj="createDataSourceFormEndpointField"]') .focus() diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index efd021c47..487413e4c 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -91,12 +91,15 @@ Cypress.Commands.add('loginWithSamlMultiauth', () => { cy.get('button[id=btn-sign-in]').should('be.visible').click(); }); -Cypress.Commands.overwrite('visit', (orig, url, options = {}) => { - if (Cypress.env('LOGIN_AS_ADMIN')) { - options.auth = ADMIN_AUTH; - } - orig(url, options); -}); +if (Cypress.env('LOGIN_AS_ADMIN')) { + // Define custom cy.visit() only if LOGIN_AS_ADMIN is true + Cypress.Commands.overwrite('visit', (orig, url, options = {}) => { + if (Cypress.env('LOGIN_AS_ADMIN')) { + options.auth = ADMIN_AUTH; + } + orig(url, options); + }); +} Cypress.Commands.add('shortenUrl', (data, tenant) => { cy.request({ From fac2dac1c32273390598dfcb0da7ce28ba0de29f Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 19:03:48 -0400 Subject: [PATCH 22/27] Try request instead of UI Signed-off-by: Derek Ho --- .../multi_datasources_enabled.spec.js | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js index 68655f71a..35de36c36 100644 --- a/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js +++ b/test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js @@ -14,22 +14,26 @@ */ const createDataSource = () => { - cy.visit('http://localhost:5601/app/management/opensearch-dashboards/dataSources/create', { - failOnStatusCode: false, + cy.request({ + method: 'POST', + url: `${Cypress.config('baseUrl')}/api/saved_objects/data-source`, + headers: { + 'osd-xsrf': true, + }, + body: { + attributes: { + title: `9202`, + endpoint: `http://localhost:9202`, + auth: { + type: 'username_password', + credentials: { + username: 'admin', + password: 'myStrongPassword123!', + }, + }, + }, + }, }); - cy.get('[data-test-subj="createDataSourceFormTitleField"]').focus().type('9202'); - cy.get('[data-test-subj="createDataSourceFormEndpointField"]') - .focus() - .type('http://localhost:9202'); - cy.get('[data-test-subj="createDataSourceFormUsernameField"]').focus().type('admin'); - cy.get('[data-test-subj="createDataSourceFormPasswordField"]') - .focus() - .type('myStrongPassword123!'); - cy.get('[data-test-subj="createDataSourceTestConnectionButton"]').click(); - cy.get('.euiToastHeader__title').should('contain', 'successful'); - cy.get('[data-test-subj="createDataSourceButton"]').click({ force: true }); - // Wait for dataSource to be created - cy.url().should('eq', 'http://localhost:5601/app/management/opensearch-dashboards/dataSources'); }; const deleteAllDataSources = () => { From 997fdbd90a6e0daec3af4fa2b1868ec41cc73861 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 19:04:25 -0400 Subject: [PATCH 23/27] Expose port Signed-off-by: Derek Ho --- .../workflows/cypress-test-multidatasources-disabled-e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml index f20478ddb..e41de5fab 100644 --- a/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml +++ b/.github/workflows/cypress-test-multidatasources-disabled-e2e.yml @@ -28,7 +28,7 @@ jobs: if: ${{ runner.os == 'Linux' }} run: | cat << 'EOT' > opensearch_dashboards_multidatasources.yml - server.host: "localhost" + server.host: "0.0.0.0" opensearch.hosts: ["https://localhost:9200"] opensearch.ssl.verificationMode: none opensearch.username: "kibanaserver" From 21a0d3ea32b31bd85229e6c415824baf10accb96 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Mon, 18 Mar 2024 23:35:26 -0400 Subject: [PATCH 24/27] Fix Signed-off-by: Derek Ho --- test/cypress/support/commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 487413e4c..8148e797f 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -96,6 +96,7 @@ if (Cypress.env('LOGIN_AS_ADMIN')) { Cypress.Commands.overwrite('visit', (orig, url, options = {}) => { if (Cypress.env('LOGIN_AS_ADMIN')) { options.auth = ADMIN_AUTH; + options.failOnStatusCode = false; } orig(url, options); }); From 65a2e99f2ae0495f3d1b6bee6ddbb34712e83eb9 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Tue, 19 Mar 2024 11:15:47 -0400 Subject: [PATCH 25/27] Headed Signed-off-by: Derek Ho --- .github/workflows/cypress-test-multidatasources-enabled-e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml index 2e6dd8ce6..5a97342bb 100644 --- a/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml +++ b/.github/workflows/cypress-test-multidatasources-enabled-e2e.yml @@ -117,4 +117,4 @@ jobs: uses: ./.github/actions/run-cypress-tests with: dashboards_config_file: opensearch_dashboards_multidatasources.yml - yarn_command: 'yarn cypress:run --browser chrome --headless --env LOGIN_AS_ADMIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' + yarn_command: 'yarn cypress:run --browser chrome --headed --env LOGIN_AS_ADMIN=true --spec "test/cypress/e2e/multi-datasources/multi_datasources_enabled.spec.js"' From e79bce632bdc067f890b6734469751874fd573c1 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Tue, 19 Mar 2024 12:23:13 -0400 Subject: [PATCH 26/27] Add security param Signed-off-by: Derek Ho --- test/cypress/support/commands.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 8148e797f..c586679b4 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -97,6 +97,9 @@ if (Cypress.env('LOGIN_AS_ADMIN')) { if (Cypress.env('LOGIN_AS_ADMIN')) { options.auth = ADMIN_AUTH; options.failOnStatusCode = false; + options.qs = { + security_tenant: 'private', + } } orig(url, options); }); From be2c0fbcdf9ea49feb92b3d8f79302c44d8b3dd4 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Tue, 19 Mar 2024 12:46:16 -0400 Subject: [PATCH 27/27] Lint Signed-off-by: Derek Ho --- test/cypress/support/commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index c586679b4..cdab9ed22 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -99,7 +99,7 @@ if (Cypress.env('LOGIN_AS_ADMIN')) { options.failOnStatusCode = false; options.qs = { security_tenant: 'private', - } + }; } orig(url, options); });