Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saved Object Aggregation View #1146

Merged
merged 14 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions .github/workflows/cypress-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: Cypress Tests

on: [push, pull_request]

env:
TEST_BROWSER_HEADLESS: 1
CI: 1
FTR_PATH: 'ftr'
START_CMD: 'node ../scripts/opensearch_dashboards --dev --no-base-path --no-watch --opensearch_security.multitenancy.enable_aggregation_view=true'
OPENSEARCH_SNAPSHOT_CMD: 'node ../scripts/opensearch snapshot'
SPEC: 'cypress/integration/plugins/security-dashboards-plugin/aggregation_view.js,'
Copy link
Member

@DarshitChanpura DarshitChanpura Oct 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this changed to a folder path? Could be done in future if we are planning to add and test more cypress tests.


jobs:
tests:
peternied marked this conversation as resolved.
Show resolved Hide resolved
name: Run aggregation view cypress test
runs-on: ubuntu-latest
steps:
- name: Download OpenSearch Core
run: |
wget https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/3.0.0/latest/linux/x64/tar/builds/opensearch/dist/opensearch-min-3.0.0-linux-x64.tar.gz
tar -xzf opensearch-*.tar.gz
rm -f opensearch-*.tar.gz

- name: Download OpenSearch Security Plugin
run: wget -O opensearch-security.zip https://ci.opensearch.org/ci/dbc/distribution-build-opensearch/3.0.0/latest/linux/x64/tar/builds/opensearch/plugins/opensearch-security-3.0.0.0.zip


- name: Run OpenSearch with plugin
run: |
cat > os-ep.sh <<EOF
yes | opensearch-plugin install file:///docker-host/security-plugin.zip
chmod +x plugins/opensearch-security/tools/install_demo_configuration.sh
yes | plugins/opensearch-security/tools/install_demo_configuration.sh
echo "plugins.security.unsupported.restapi.allow_securityconfig_modification: true" >> /opensearch/config/opensearch.yml
chown 1001:1001 -R /opensearch
su -c "/opensearch/bin/opensearch" -s /bin/bash opensearch
EOF
docker build -t opensearch-test:latest -f- . <<EOF
FROM ubuntu:latest
COPY --chown=1001:1001 os-ep.sh /docker-host/
COPY --chown=1001:1001 opensearch-security.zip /docker-host/security-plugin.zip
COPY --chown=1001:1001 opensearch* /opensearch/
RUN chmod +x /docker-host/os-ep.sh
RUN useradd -u 1001 -s /sbin/nologin opensearch
ENV PATH="/opensearch/bin:${PATH}"
WORKDIR /opensearch/
ENTRYPOINT /docker-host/os-ep.sh
EOF
docker run -d -p 9200:9200 -p 9600:9600 -i opensearch-test:latest

- name: Checkout OpenSearch Dashboard
uses: actions/checkout@v2
with:
path: OpenSearch-Dashboards
repository: opensearch-project/OpenSearch-Dashboards
ref: 'main'
fetch-depth: 0

- name: Create plugins dir
run: |
cd ./OpenSearch-Dashboards
mkdir -p plugins

- name: Checkout OpenSearch Dashboard Security plugin
uses: actions/checkout@v2
with:
path: OpenSearch-Dashboards/plugins/security-dashboards-plugin
ref: ${{ github.ref }}

- name: Check OpenSearch Running
continue-on-error: true
run: curl -XGET https://localhost:9200 -u 'admin:admin' -k

- name: Get node and yarn versions
id: versions
run: |
echo "::set-output name=node_version::$(cat ./OpenSearch-Dashboards/.node-version)"
echo "::set-output name=yarn_version::$(jq -r '.engines.yarn' ./OpenSearch-Dashboards/package.json)"

- name: Setup node
uses: actions/setup-node@v1
with:
node-version: ${{ steps.versions.outputs.node_version }}
registry-url: 'https://registry.npmjs.org'

- name: Install correct yarn version for OpenSearch Dashboards
run: |
npm uninstall -g yarn
echo "Installing yarn ${{ steps.versions_step.outputs.yarn_version }}"
npm i -g yarn@${{ steps.versions.outputs.yarn_version }}

- name: Check OpenSearch Running
continue-on-error: true
run: curl -XGET https://localhost:9200 -u 'admin:admin' -k

- name: Bootstrap OpenSearch Dashboards
continue-on-error: false
run: |
cd ./OpenSearch-Dashboards
yarn osd bootstrap
echo 'server.host: "0.0.0.0"' >> ./config/opensearch_dashboards.yml
echo 'opensearch.hosts: ["https://localhost:9200"]' >> ./config/opensearch_dashboards.yml
echo 'opensearch.ssl.verificationMode: none' >> ./config/opensearch_dashboards.yml
echo 'opensearch.username: "kibanaserver"' >> ./config/opensearch_dashboards.yml
echo 'opensearch.password: "kibanaserver"' >> ./config/opensearch_dashboards.yml
echo 'opensearch.requestHeadersWhitelist: [ authorization,securitytenant ]' >> ./config/opensearch_dashboards.yml
echo 'opensearch_security.multitenancy.enabled: true' >> ./config/opensearch_dashboards.yml
echo 'opensearch_security.multitenancy.tenants.preferred: ["Private", "Global"]' >> ./config/opensearch_dashboards.yml
echo 'opensearch_security.readonly_mode.roles: ["kibana_read_only"]' >> ./config/opensearch_dashboards.yml
echo 'opensearch_security.cookie.secure: false' >> ./config/opensearch_dashboards.yml
echo 'opensearch_security.multitenancy.enable_aggregation_view: true' >> ./config/opensearch_dashboards.yml
yarn start --no-base-path --no-watch &
sleep 300

- name: Checkout
uses: actions/checkout@v2
with:
path: ${{ env.FTR_PATH }}
repository: RyanL1997/opensearch-dashboards-functional-test
peternied marked this conversation as resolved.
Show resolved Hide resolved
ref: 'saved-objects-test'

- name: Get Cypress version
id: cypress_version
run: |
echo "::set-output name=cypress_version::$(cat ./${{ env.FTR_PATH }}/package.json | jq '.devDependencies.cypress' | tr -d '"')"

- name: Run tests
uses: cypress-io/github-action@v2
with:
working-directory: ${{ env.FTR_PATH }}
command: yarn cypress:run-with-security-and-aggregation-view --browser chromium --spec ${{ env.SPEC }}
peternied marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "3.0.0.0",
"opensearchDashboardsVersion": "3.0.0",
"configPath": ["opensearch_security"],
"requiredPlugins": ["navigation"],
"requiredPlugins": ["navigation", "savedObjectsManagement"],
DarshitChanpura marked this conversation as resolved.
Show resolved Hide resolved
"server": true,
"ui": true
}
12 changes: 9 additions & 3 deletions public/apps/account/account-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { AccountNavButton } from './account-nav-button';
import { fetchAccountInfoSafe } from './utils';
import { ClientConfigType } from '../../types';
import { CUSTOM_ERROR_PAGE_URI, ERROR_MISSING_ROLE_PATH } from '../../../common';
import { selectTenant } from '../configuration/utils/tenant-utils';
import { fetchCurrentTenant, selectTenant } from '../configuration/utils/tenant-utils';
import {
getSavedTenant,
getShouldShowTenantPopup,
Expand All @@ -44,7 +44,13 @@ export async function setupTopNavButton(coreStart: CoreStart, config: ClientConf
coreStart.http.basePath.serverBasePath + CUSTOM_ERROR_PAGE_URI + ERROR_MISSING_ROLE_PATH;
}

let tenant = accountInfo.user_requested_tenant;
let tenant: string | undefined;
if (config.multitenancy.enabled && config.multitenancy.enable_aggregation_view) {
tenant = await fetchCurrentTenant(coreStart.http);
} else {
tenant = accountInfo.user_requested_tenant;
}

let shouldShowTenantPopup = true;

if (tenantSpecifiedInUrl() || getShouldShowTenantPopup() === false) {
Expand All @@ -67,7 +73,7 @@ export async function setupTopNavButton(coreStart: CoreStart, config: ClientConf
window.location.reload();
}
}
} catch (e) {
} catch (e: any) {
constructErrorMessageAndLog(e, `Failed to switch to ${tenant} tenant.`);
}
}
Expand Down
3 changes: 2 additions & 1 deletion public/apps/account/account-nav-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,10 @@ export function AccountNavButton(props: {
setModal(null);
window.location.reload();
}}
tenant={props.tenant!}
DarshitChanpura marked this conversation as resolved.
Show resolved Hide resolved
/>
),
[props.config, props.coreStart]
[props.config, props.coreStart, props.tenant]
);

// Check if the tenant modal should be shown on load
Expand Down
14 changes: 11 additions & 3 deletions public/apps/account/tenant-switch-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ interface TenantSwitchPanelProps {
handleClose: () => void;
handleSwitchAndClose: () => void;
config: ClientConfigType;
tenant: string;
}

const GLOBAL_TENANT_KEY_NAME = 'global_tenant';
Expand Down Expand Up @@ -90,8 +91,15 @@ export function TenantSwitchPanel(props: TenantSwitchPanelProps) {
const currentUserName = accountInfo.data.user_name;
setUsername(currentUserName);

// @ts-ignore
const currentRawTenantName = accountInfo.data.user_requested_tenant;
let currentRawTenantName: string | undefined;
if (
props.config.multitenancy.enabled &&
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
props.config.multitenancy.enable_aggregation_view
) {
currentRawTenantName = props.tenant;
} else {
currentRawTenantName = accountInfo.data.user_requested_tenant;
}
setCurrentTenant(currentRawTenantName || '', currentUserName);
} catch (e) {
// TODO: switch to better error display.
Expand All @@ -100,7 +108,7 @@ export function TenantSwitchPanel(props: TenantSwitchPanelProps) {
};

fetchData();
}, [props.coreStart.http]);
}, [props.coreStart.http, props.tenant, props.config.multitenancy]);

// Custom tenant super select related.
const onCustomTenantChange = (selectedOption: EuiComboBoxOptionOption[]) => {
Expand Down
18 changes: 14 additions & 4 deletions public/apps/account/test/account-app.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
getSavedTenant,
} from '../../../utils/storage-utils';
import { fetchAccountInfoSafe } from '../utils';
import { selectTenant } from '../../configuration/utils/tenant-utils';
import { fetchCurrentTenant, selectTenant } from '../../configuration/utils/tenant-utils';

jest.mock('../../../utils/storage-utils', () => ({
getShouldShowTenantPopup: jest.fn(),
Expand All @@ -36,6 +36,7 @@ jest.mock('../utils', () => ({

jest.mock('../../configuration/utils/tenant-utils', () => ({
selectTenant: jest.fn(),
fetchCurrentTenant: jest.fn(),
}));

describe('Account app', () => {
Expand All @@ -47,6 +48,12 @@ describe('Account app', () => {
},
};

const mockConfig = {
multitenancy: {
enable_aggregation_view: true,
},
};

const mockAccountInfo = {
data: {
roles: {
Expand All @@ -55,8 +62,11 @@ describe('Account app', () => {
},
};

const mockTenant = 'test1';

beforeAll(() => {
(fetchAccountInfoSafe as jest.Mock).mockResolvedValue(mockAccountInfo);
(fetchCurrentTenant as jest.Mock).mockResolvedValue(mockTenant);
});

it('Should skip if auto swich if securitytenant in url', (done) => {
Expand All @@ -65,7 +75,7 @@ describe('Account app', () => {
delete window.location;
window.location = new URL('http://www.example.com?securitytenant=abc') as any;

setupTopNavButton(mockCoreStart, {} as any);
setupTopNavButton(mockCoreStart, mockConfig as any);

process.nextTick(() => {
expect(setShouldShowTenantPopup).toBeCalledWith(false);
Expand All @@ -77,7 +87,7 @@ describe('Account app', () => {
it('Should switch to saved tenant when securitytenant not in url', (done) => {
(getSavedTenant as jest.Mock).mockReturnValueOnce('tenant1');

setupTopNavButton(mockCoreStart, {} as any);
setupTopNavButton(mockCoreStart, mockConfig as any);

process.nextTick(() => {
expect(getSavedTenant).toBeCalledTimes(1);
Expand All @@ -92,7 +102,7 @@ describe('Account app', () => {
it('Should show tenant selection popup when neither securitytenant in url nor saved tenant', (done) => {
(getSavedTenant as jest.Mock).mockReturnValueOnce(null);

setupTopNavButton(mockCoreStart, {} as any);
setupTopNavButton(mockCoreStart, mockConfig as any);

process.nextTick(() => {
expect(getSavedTenant).toBeCalledTimes(1);
Expand Down
4 changes: 2 additions & 2 deletions public/apps/configuration/configuration-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import React from 'react';
import ReactDOM from 'react-dom';
import { I18nProvider } from '@osd/i18n/react';
import { AppMountParameters, CoreStart } from '../../../../../src/core/public';
import { AppPluginStartDependencies, ClientConfigType } from '../../types';
import { SecurityPluginStartDependencies, ClientConfigType } from '../../types';
import { AppRouter } from './app-router';

export function renderApp(
coreStart: CoreStart,
navigation: AppPluginStartDependencies,
navigation: SecurityPluginStartDependencies,
params: AppMountParameters,
config: ClientConfigType
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function ClusterPermissionPanel(props: {
options={optionUniverse}
selectedOptions={state}
onChange={setState}
id="roles-cluster-permission-box"
/>
</EuiFlexItem>
{/* TODO: 'Browse and select' button with a pop-up modal for selection */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,16 @@ export function IndexPatternRow(props: {
}) {
return (
<FormRow headerText="Index" helpText="Specify index pattern using *">
<EuiComboBox
noSuggestions
placeholder="Search for index name or type in index pattern"
selectedOptions={props.value}
onChange={props.onChangeHandler}
onCreateOption={props.onCreateHandler}
/>
<EuiFlexItem className={LIMIT_WIDTH_INPUT_CLASS}>
<EuiComboBox
noSuggestions
placeholder="Search for index name or type in index pattern"
selectedOptions={props.value}
onChange={props.onChangeHandler}
onCreateOption={props.onCreateHandler}
id="index-input-box"
/>
</EuiFlexItem>
</FormRow>
);
}
Expand All @@ -150,6 +153,7 @@ export function IndexPermissionRow(props: {
options={props.permisionOptionsSet}
selectedOptions={props.value}
onChange={props.onChangeHandler}
id="roles-index-permission-box"
/>
</EuiFlexItem>
{/* TODO: 'Browse and select' button with a pop-up modal for selection */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ function generateTenantPermissionPanels(
onChange={onValueChangeHandler('tenantPatterns')}
onCreateOption={onCreateOptionHandler('tenantPatterns')}
options={permisionOptionsSet}
id="roles-tenant-permission-box"
/>
</EuiFlexItem>
<EuiFlexItem style={{ maxWidth: '170px' }}>
Expand Down
17 changes: 14 additions & 3 deletions public/apps/configuration/utils/tenant-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ import { httpDelete, httpGet, httpPost } from './request-utils';
import { getResourceUrl } from './resource-utils';

export const globalTenantName = 'global_tenant';
export const GLOBAL_TENANT = '';
export const PRIVATE_TENANT = '__user__';
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
export const DEFAULT_TENANT = 'default';
export const GLOBAL_USER_DICT: { [key: string]: string } = {
Label: 'Global',
Value: '',
Value: GLOBAL_TENANT,
Description: 'Everyone can see it',
};

Expand All @@ -62,10 +65,10 @@ export function transformTenantData(
): Tenant[] {
// @ts-ignore
const tenantList: Tenant[] = map<Tenant, Tenant>(rawTenantData, (v: Tenant, k?: string) => ({
tenant: k === globalTenantName ? GLOBAL_USER_DICT.Label : k || '',
tenant: k === globalTenantName ? GLOBAL_USER_DICT.Label : k || GLOBAL_TENANT,
reserved: v.reserved,
description: k === globalTenantName ? GLOBAL_USER_DICT.Description : v.description,
tenantValue: k === globalTenantName ? GLOBAL_USER_DICT.Value : k || '',
tenantValue: k === globalTenantName ? GLOBAL_USER_DICT.Value : k || GLOBAL_TENANT,
}));
if (isPrivateEnabled) {
// Insert Private Tenant in List
Expand Down Expand Up @@ -170,3 +173,11 @@ export function transformRoleTenantPermissions(
permissionType: getTenantPermissionType(tenantPermission.allowed_actions),
}));
}

export function isPrivateTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant?.startsWith(PRIVATE_TENANT);
cliu123 marked this conversation as resolved.
Show resolved Hide resolved
}

export function isGlobalTenant(selectedTenant: string | null) {
return selectedTenant !== null && selectedTenant === GLOBAL_TENANT;
}
Loading