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

Multi-tenancy support for trace analytics #1404

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f1f2739
Add configuration for multi-tenancy
JulianQuispel Feb 2, 2024
e2ec3fd
Merge branch 'opensearch-project:main' into feature/multitenancy
JulianQuispel Feb 2, 2024
882b2b6
Update indices route to support tenants
JulianQuispel Feb 2, 2024
bee7ee9
Merge branch 'feature/multitenancy' of github.com:JulianQuispel/dashb…
JulianQuispel Feb 2, 2024
8787067
Update components to be aware of the current tenant
JulianQuispel Feb 2, 2024
df0b93e
Merge branch 'opensearch-project:main' into feature/multitenancy
JulianQuispel Feb 5, 2024
a53308e
Fix undefined tenant
JulianQuispel Feb 7, 2024
551077c
Merge branch 'feature/multitenancy' of github.com:JulianQuispel/dashb…
JulianQuispel Feb 7, 2024
89199bb
Merge branch 'main' into feature/multitenancy
JulianQuispel Feb 7, 2024
a55978c
Remove tenant from queries
JulianQuispel Feb 8, 2024
395a3fa
Merge branch 'feature/multitenancy' of github.com:JulianQuispel/dashb…
JulianQuispel Feb 8, 2024
0daad29
Merge branch 'main' into feature/multitenancy
JulianQuispel Feb 9, 2024
0f4fb09
Merge branch 'main' into feature/multitenancy
JulianQuispel Feb 16, 2024
867ef53
Merge branch 'main' into feature/multitenancy
JulianQuispel Feb 20, 2024
10b0339
Merge branch 'main' into feature/multitenancy
JulianQuispel Feb 26, 2024
9a4183d
Merge remote-tracking branch 'origin/main' into feature/multitenancy
JulianQuispel Mar 11, 2024
087b827
Merge branch 'feature/multitenancy' of github.com:JulianQuispel/dashb…
JulianQuispel Mar 11, 2024
941d4c8
Merge branch 'main' of https://github.com/opensearch-project/dashboar…
JulianQuispel Mar 11, 2024
5305ddc
Merge branch 'main' into feature/multitenancy
JulianQuispel Apr 29, 2024
20c2749
Remove unused imports and logs
JulianQuispel May 2, 2024
cb1496a
Merge branch 'main' of https://github.com/opensearch-project/dashboar…
JulianQuispel May 2, 2024
b6b8117
Replace fetch with http
JulianQuispel May 2, 2024
21c61cc
fix runtime errors
joshuali925 May 2, 2024
298febd
Merge branch 'main' into feature/multitenancy
ps48 May 21, 2024
3ad8c16
Merge branch 'main' into feature/multitenancy
JulianQuispel May 27, 2024
f519b79
Update public/components/trace_analytics/home.tsx
JulianQuispel May 27, 2024
290203a
Swap lines in trace analytics home
JulianQuispel May 27, 2024
d6a0202
Merge branch 'feature/multitenancy' of github.com:JulianQuispel/dashb…
JulianQuispel May 27, 2024
b8e94d7
Add dataSourceMDSId
JulianQuispel May 27, 2024
9210dac
Add dataSourceMDSId to handleDashboardErrorRatePltRequest
JulianQuispel May 27, 2024
943be36
Merged incoming synced main
JoeriRoijenga Aug 6, 2024
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
6 changes: 5 additions & 1 deletion .cypress/integration/panels_test/panels.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ describe('Panels testing with Sample Data', { defaultCommandTimeout: 10000 }, ()
// cy.get('[id^=autocomplete-textarea]').focus().type(PPL_VISUALIZATIONS[1], {
// delay: 50,
// });
cy.get('[id^=autocomplete-textarea]').focus().invoke('val', PPL_VISUALIZATIONS[1]).trigger('input').trigger('change');
cy.get('[id^=autocomplete-textarea]')
.focus()
.invoke('val', PPL_VISUALIZATIONS[1])
.trigger('input')
.trigger('change');
cy.get('.euiButton__text').contains('Run').trigger('mouseover').click();
cy.get('button[id="main-content-vis"]')
.contains('Visualizations')
Expand Down
17 changes: 17 additions & 0 deletions common/utils/tenant_index_name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

export function getTenantIndexName(indexName: string, tenantName?: string) {
if (indexName.charAt(indexName.length - 1) === '*') {
indexName = indexName.slice(0, -1);
}

if (tenantName) {
if (indexName.charAt(indexName.length - 1) !== '-') indexName += '-';
indexName += `${tenantName.toLowerCase()}`;
}

return indexName + '*';
}
5 changes: 4 additions & 1 deletion public/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ interface ObservabilityAppDeps {
pplService: any;
dslService: any;
savedObjects: any;
config: PublicConfig;
timestampUtils: any;
queryManager: QueryManager;
startPage: string;
Expand Down Expand Up @@ -59,6 +60,7 @@ export const App = ({
pplService,
dslService,
savedObjects,
config,
timestampUtils,
queryManager,
startPage,
Expand All @@ -68,7 +70,7 @@ export const App = ({
dataSourceEnabled,
savedObjectsMDSClient,
}: ObservabilityAppDeps) => {
const { chrome, http, notifications, savedObjects: coreSavedObjects } = CoreStartProp;
const { chrome, http, notifications } = CoreStartProp;
const parentBreadcrumb = {
text: observabilityTitle,
href: `${observabilityID}#/`,
Expand All @@ -92,6 +94,7 @@ export const App = ({
pplService={pplService}
dslService={dslService}
savedObjects={savedObjects}
config={config}
timestampUtils={timestampUtils}
queryManager={queryManager}
parentBreadcrumb={parentBreadcrumb}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ServiceConfig = (props: ServiceConfigProps) => {
http,
selectedServices,
setSelectedServices,
tenant,
} = props;
const { mode } = props;
const [servicesOpen, setServicesOpen] = useState(false);
Expand All @@ -49,7 +50,7 @@ export const ServiceConfig = (props: ServiceConfigProps) => {
const [modalLayout, setModalLayout] = useState(<EuiOverlayMask />);

useEffect(() => {
handleServiceMapRequest(http, dslService, mode, '', setServiceMap);
handleServiceMapRequest(http, dslService, mode, '', setServiceMap, undefined, tenant);
}, []);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function ServiceDetailFlyout(props: ServiceFlyoutProps) {
closeServiceFlyout,
openSpanFlyout,
mode,
tenant,
} = props;
const [fields, setFields] = useState<any>({});
const [serviceMap, setServiceMap] = useState<ServiceObject>({});
Expand Down Expand Up @@ -131,7 +132,7 @@ export function ServiceDetailFlyout(props: ServiceFlyoutProps) {
appConfigs
);
handleServiceViewRequest(serviceName, http, serviceDSL, setFields, mode);
handleServiceMapRequest(http, serviceDSL, mode, '', setServiceMap, serviceName);
handleServiceMapRequest(http, serviceDSL, mode, '', setServiceMap, serviceName, tenant);
const spanDSL = filtersToDsl(mode, filters, query, startTime, endTime, 'app', appConfigs);
spanDSL.query.bool.must.push({
term: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@ interface TraceDetailRenderProps {
traceId: string;
http: HttpStart;
openSpanFlyout: (spanId: string) => void;
mode : TraceAnalyticsMode
mode: TraceAnalyticsMode;
tenant?: string;
}

export const TraceDetailRender = ({ traceId, http, openSpanFlyout, mode }: TraceDetailRenderProps) => {
export const TraceDetailRender = ({
traceId,
http,
openSpanFlyout,
mode,
tenant,
}: TraceDetailRenderProps) => {
const [fields, setFields] = useState<any>({});
const [serviceBreakdownData, setServiceBreakdownData] = useState([]);
const [payloadData, setPayloadData] = useState('');
Expand Down Expand Up @@ -86,9 +93,16 @@ export const TraceDetailRender = ({ traceId, http, openSpanFlyout, mode }: Trace
}, [traceId, fields, serviceBreakdownData, colorMap, payloadData]);

useEffect(() => {
handleTraceViewRequest(traceId, http, fields, setFields, mode);
handleServicesPieChartRequest(traceId, http, setServiceBreakdownData, setColorMap, mode);
handlePayloadRequest(traceId, http, payloadData, setPayloadData, mode);
handleTraceViewRequest(traceId, http, fields, setFields, mode, tenant);
handleServicesPieChartRequest(
traceId,
http,
setServiceBreakdownData,
setColorMap,
mode,
tenant
);
handlePayloadRequest(traceId, http, payloadData, setPayloadData, mode, tenant);
}, [traceId]);

return renderContent;
Expand Down
5 changes: 0 additions & 5 deletions public/components/event_analytics/explorer/log_explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ import { selectQueries } from '../redux/slices/query_slice';
import { selectQueryTabs } from '../redux/slices/query_tab_slice';
import { Explorer } from './explorer';
import { getDateRange } from '../utils/utils';
import {
QUERY_ASSIST_END_TIME,
QUERY_ASSIST_START_TIME,
} from '../../../../common/constants/shared';
import { coreRefs } from '../../../../public/framework/core_refs';

const searchBarConfigs = {
[TAB_EVENT_ID]: {
Expand Down
5 changes: 4 additions & 1 deletion public/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { AppMountParameters, CoreStart } from '../../../../src/core/public';
import { DataSourceManagementPluginSetup } from '../../../../src/plugins/data_source_management/public';
import { AppPluginStartDependencies } from '../types';
import { App } from './app';
import { PublicConfig } from '../plugin';

export const Observability = (
CoreStartProp: CoreStart,
Expand All @@ -23,7 +24,8 @@ export const Observability = (
startPage: string,
dataSourcePluggables,
dataSourceManagement: DataSourceManagementPluginSetup,
savedObjectsMDSClient: CoreStart['savedObjects']
savedObjectsMDSClient: CoreStart['savedObjects'],
config: PublicConfig
) => {
const { setHeaderActionMenu } = AppMountParametersProp;
const { dataSource } = DepsStart;
Expand All @@ -34,6 +36,7 @@ export const Observability = (
pplService={pplService}
dslService={dslService}
savedObjects={savedObjects}
config={config}
timestampUtils={timestampUtils}
queryManager={queryManager}
startPage={startPage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,33 @@ exports[`Helper functions renders no match and missing configuration messages 2`
</Fragment>
`;

exports[`Helper functions renders no match and missing configuration messages 3`] = `
<Fragment>
<EuiEmptyPrompt
actions={
<EuiButton
color="primary"
iconSide="right"
iconType="popout"
onClick={[Function]}
>
Learn more
</EuiButton>
}
body={
<EuiText>
The indices required for trace analytics (otel-v1-apm-span-test* and otel-v1-apm-service-map-test*) do not exist or you do not have permission to access them.
</EuiText>
}
title={
<h2>
Trace Analytics not set up
</h2>
}
/>
</Fragment>
`;

exports[`Helper functions renders panel title 1`] = `
<EuiText
size="m"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import { configure, mount, shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { TraceAnalyticsMode } from 'public/components/trace_analytics/home';
import React from 'react';
import { TEST_SERVICE_MAP, TEST_SERVICE_MAP_GRAPH } from '../../../../../../test/constants';
import {
Expand Down Expand Up @@ -38,9 +37,15 @@ describe('Helper functions', () => {

it('renders no match and missing configuration messages', () => {
const noMatchMessage = shallow(<NoMatchMessage size="s" />);
const missingConfigurationMessage = shallow(<MissingConfigurationMessage mode='data_prepper'/>)
const missingConfigurationMessage = shallow(
<MissingConfigurationMessage mode="data_prepper" />
);
const missingConfigurationMessageWithTenant = shallow(
<MissingConfigurationMessage mode="data_prepper" tenant="test" />
);
expect(noMatchMessage).toMatchSnapshot();
expect(missingConfigurationMessage).toMatchSnapshot();
expect(missingConfigurationMessageWithTenant).toMatchSnapshot();
});

it('renders benchmark', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ import { TraceAnalyticsMode } from '../../home';
import { serviceMapColorPalette } from './color_palette';
import { FilterType } from './filters/filters';
import { ServiceObject } from './plots/service_map';

const missingJaegerTracesConfigurationMessage = `The indices required for trace analytics (${JAEGER_INDEX_NAME} and ${JAEGER_SERVICE_INDEX_NAME}) do not exist or you do not have permission to access them.`;

const missingDataPrepperTracesConfigurationMessage = `The indices required for trace analytics (${DATA_PREPPER_INDEX_NAME} and ${DATA_PREPPER_SERVICE_INDEX_NAME}) do not exist or you do not have permission to access them.`;
import { getTenantIndexName } from '../../../../../common/utils/tenant_index_name';

export function PanelTitle({ title, totalItems }: { title: string; totalItems?: number }) {
return (
Expand Down Expand Up @@ -55,7 +52,23 @@ export function NoMatchMessage(props: { size: SpacerSize }) {
);
}

export function MissingConfigurationMessage(props: { mode: TraceAnalyticsMode }) {
export function MissingConfigurationMessage(props: { mode: TraceAnalyticsMode; tenant?: string }) {
const missingJaegerTracesConfigurationMessage = `The indices required for trace analytics (${getTenantIndexName(
JAEGER_INDEX_NAME,
props.tenant
)} and ${getTenantIndexName(
JAEGER_SERVICE_INDEX_NAME,
props.tenant
)}) do not exist or you do not have permission to access them.`;

const missingDataPrepperTracesConfigurationMessage = `The indices required for trace analytics (${getTenantIndexName(
DATA_PREPPER_INDEX_NAME,
props.tenant
)} and ${getTenantIndexName(
DATA_PREPPER_SERVICE_INDEX_NAME,
props.tenant
)}) do not exist or you do not have permission to access them.`;

const missingConfigurationBody =
props.mode === 'jaeger'
? missingJaegerTracesConfigurationMessage
Expand Down
28 changes: 28 additions & 0 deletions public/components/trace_analytics/components/common/indices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { CoreStart } from '../../../../../../../src/core/public';

export async function loadTenantInfo(http: CoreStart['http'], multitenancyEnabled: boolean) {
if (!multitenancyEnabled) {
return;
}

return await http
.get('/api/v1/multitenancy/tenant')
.then((tenant) => {
if (tenant === '' || tenant === '__user__') {
tenant = '';
}
return tenant;
})
.catch((error) => {
if (error.body.statusCode === 404) {
// endpoint doesn't exist, security plugin is not enabled.
return undefined;
}
console.error(`failed to request tenant: ${String(error)}`);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import React from 'react';
import { Dashboard } from '..';
// eslint-disable-next-line jest/no-mocks-import
import { coreStartMock } from '../../../../../../test/__mocks__/coreMocks';

describe('Dashboard component', () => {
Expand Down
Loading
Loading