Skip to content

Commit

Permalink
Add cloudwatch logs as a datasource
Browse files Browse the repository at this point in the history
Signed-off-by: Derek Ho <dxho@amazon.com>
  • Loading branch information
derek-ho committed Oct 10, 2023
1 parent 4a8b500 commit 6a7f80a
Show file tree
Hide file tree
Showing 8 changed files with 457 additions and 2 deletions.
1 change: 1 addition & 0 deletions common/constants/data_connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const QUERY_ALL = 'query-all';
export const DatasourceTypeToDisplayName: { [key in DatasourceType]: string } = {
PROMETHEUS: 'Prometheus',
S3GLUE: 'Amazon S3',
CLOUDWATCHLOGS: 'Amazon CloudWatch',
};

export type AuthMethod = 'noauth' | 'basicauth' | 'awssigv4';
2 changes: 1 addition & 1 deletion common/types/data_connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ export interface PermissionsConfigurationProps {

export type Role = EuiComboBoxOptionOption;

export type DatasourceType = 'S3GLUE' | 'PROMETHEUS';
export type DatasourceType = 'S3GLUE' | 'PROMETHEUS' | 'CLOUDWATCHLOGS';
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import {
EuiPanel,
EuiTitle,
EuiSpacer,
EuiText,
EuiLink,
EuiFormRow,
EuiFieldText,
EuiTextArea,
EuiSelect,
} from '@elastic/eui';
import React, { useState } from 'react';
import {
AuthMethod,
OPENSEARCH_DOCUMENTATION_URL,
} from '../../../../../common/constants/data_connections';
import { QueryPermissionsConfiguration } from './query_permissions';
import { Role } from '../../../../../common/types/data_connections';
import { AuthDetails } from './auth_details';
import { NameRow } from './name_row';

export interface ConfigureCloudWatchDatasourceProps {
roles: Role[];
selectedQueryPermissionRoles: Role[];
setSelectedQueryPermissionRoles: React.Dispatch<React.SetStateAction<Role[]>>;
currentName: string;
currentDetails: string;
currentArn: string;
currentStore: string;
currentAuthMethod: AuthMethod;
currentUsername: string;
currentPassword: string;
hasSecurityAccess: boolean;
error: string;
currentRegion: string;
setRegionForRequest: React.Dispatch<React.SetStateAction<string>>;
setError: React.Dispatch<React.SetStateAction<string>>;
setAuthMethodForRequest: React.Dispatch<React.SetStateAction<AuthMethod>>;
setPasswordForRequest: React.Dispatch<React.SetStateAction<string>>;
setUsernameForRequest: React.Dispatch<React.SetStateAction<string>>;
setStoreForRequest: React.Dispatch<React.SetStateAction<string>>;
setNameForRequest: React.Dispatch<React.SetStateAction<string>>;
setDetailsForRequest: React.Dispatch<React.SetStateAction<string>>;
setArnForRequest: React.Dispatch<React.SetStateAction<string>>;
}

export const ConfigureCloudWatchDatasource = (props: ConfigureCloudWatchDatasourceProps) => {
const {
setNameForRequest,
setDetailsForRequest,
setArnForRequest,
setStoreForRequest,
currentStore,
currentName,
currentDetails,
currentArn,
roles,
currentAuthMethod,
setAuthMethodForRequest,
selectedQueryPermissionRoles,
setSelectedQueryPermissionRoles,
currentPassword,
currentUsername,
setPasswordForRequest,
setUsernameForRequest,
hasSecurityAccess,
error,
setError,
currentRegion,
setRegionForRequest,
} = props;

const [details, setDetails] = useState(currentDetails);
const [arn, setArn] = useState(currentArn);
const [region, setRegion] = useState(currentRegion);
const [store, setStore] = useState(currentStore);
const authOptions = [
{ value: 'basicauth', text: 'Basic authentication' },
{ value: 'noauth', text: 'No authentication' },
];

return (
<div>
<EuiPanel>
<EuiTitle>
<h1>{`Configure Amazon CloudWatch Logs data source`}</h1>
</EuiTitle>
<EuiSpacer size="s" />
<EuiText size="s" color="subdued">
{`Connect to Amazon CloudWatch Logs with OpenSearch and OpenSearch Dashboards. `}
<EuiLink external={true} href={OPENSEARCH_DOCUMENTATION_URL} target="blank">
Learn more
</EuiLink>
</EuiText>
<EuiSpacer />
<EuiText>
<h3>Data source details</h3>
</EuiText>
<EuiSpacer />
<NameRow
key={error}
currentName={currentName}
setNameForRequest={setNameForRequest}
currentError={error}
setErrorForForm={setError}
/>
<EuiFormRow label="Description - Optional">
<EuiTextArea
placeholder="Describe data source"
value={details}
onBlur={(e) => {
setDetailsForRequest(e.target.value);
}}
onChange={(e) => {
setDetails(e.target.value);
}}
/>
</EuiFormRow>
<EuiSpacer />

<EuiText>
<h3>Amazon CloudWatch Logs</h3>
</EuiText>
<EuiSpacer />

<EuiFormRow label="Amazon CloudWatch Logs region">
<>
<EuiText size="xs">
<p>This should be the region for Amazon CloudWatch Logs</p>
</EuiText>
<EuiFieldText
data-test-subj="region"
placeholder="Region"
value={region}
onChange={(e) => {
setRegion(e.target.value);
}}
onBlur={(e) => {
setRegionForRequest(e.target.value);
}}
/>
</>
</EuiFormRow>

<EuiFormRow label="Authentication Method">
<>
<EuiText size="xs">
<p>
This parameter provides the authentication type information required for execution
engine to connect to Amazon CloudWatch Logs.
</p>
</EuiText>
<EuiFieldText data-test-subj="authentication-method" value="IAM role" disabled />
</>
</EuiFormRow>

<EuiFormRow label="Amazon CloudWatch Logs authentication ARN">
<>
<EuiText size="xs">
<p>This should be the IAM role ARN</p>
</EuiText>
<EuiFieldText
data-test-subj="role-ARN"
placeholder="Role ARN"
value={arn}
onChange={(e) => {
setArn(e.target.value);
}}
onBlur={(e) => {
setArnForRequest(e.target.value);
}}
/>
</>
</EuiFormRow>

<EuiSpacer />

<EuiText>
<h3>Amazon CloudWatch Logs index store details</h3>
</EuiText>
<EuiSpacer />

<EuiFormRow label="Amazon CloudWatch Logs index store URI">
<>
<EuiText size="xs">
<p>
This parameter provides the OpenSearch cluster host information for Amazon
CloudWatch Logs. This OpenSearch instance is used for writing index data back.
</p>
</EuiText>
<EuiFieldText
data-test-subj="index-URI"
placeholder="Index store URI"
value={store}
onChange={(e) => {
setStore(e.target.value);
}}
onBlur={(e) => {
setStoreForRequest(e.target.value);
}}
/>
</>
</EuiFormRow>

<EuiFormRow label="Amazon CloudWatch Logs index store authentication">
<>
<EuiText size="xs">
<p>Authentication settings to access the index store.</p>
</EuiText>
<EuiSelect
id="selectAuthMethod"
options={authOptions}
value={currentAuthMethod}
onChange={(e) => {
setAuthMethodForRequest(e.target.value as AuthMethod);
}}
/>
</>
</EuiFormRow>
<AuthDetails
currentUsername={currentUsername}
setUsernameForRequest={setUsernameForRequest}
currentPassword={currentPassword}
setPasswordForRequest={setPasswordForRequest}
currentAuthMethod={currentAuthMethod}
/>

<EuiSpacer />

<QueryPermissionsConfiguration
roles={roles}
selectedRoles={selectedQueryPermissionRoles}
setSelectedRoles={setSelectedQueryPermissionRoles}
layout={'vertical'}
hasSecurityAccess={hasSecurityAccess}
/>
</EuiPanel>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import {
} from '../../../../../common/constants/data_connections';
import { formatError } from '../../../../../public/components/event_analytics/utils';
import { NotificationsStart } from '../../../../../../../src/core/public';
import {
ConfigureCloudWatchDatasource,
ConfigureCloudWatchDatasourceProps,
} from './configure_cloudwatch_datasource';
import { ReviewCloudWatchDatasource } from './review_cloudwatch_datasource_configuration';

interface ConfigureDatasourceProps {
type: DatasourceType;
Expand Down Expand Up @@ -149,6 +154,33 @@ export function Configure(props: ConfigureDatasourceProps) {
setError={setError}
/>
);
case 'CLOUDWATCHLOGS':
const configureCloudWatchProps: ConfigureCloudWatchDatasourceProps = {
currentName: name,
currentDetails: details,
setNameForRequest: setName,
setDetailsForRequest: setDetails,
currentArn: arn,
setArnForRequest: setArn,
currentStore: storeURI,
setStoreForRequest: setStoreURI,
roles,
selectedQueryPermissionRoles,
setSelectedQueryPermissionRoles,
currentUsername: username,
setUsernameForRequest: setUsername,
currentPassword: password,
setPasswordForRequest: setPassword,
currentAuthMethod: authMethod,
setAuthMethodForRequest: setAuthMethod,
hasSecurityAccess,
error,
setError,
currentRegion: region,
setRegionForRequest: setRegion,
};
return <ConfigureCloudWatchDatasource {...configureCloudWatchProps} />;

default:
return <></>;
}
Expand Down Expand Up @@ -182,6 +214,19 @@ export function Configure(props: ConfigureDatasourceProps) {
goBack={() => setPage('configure')}
/>
);
case 'CLOUDWATCHLOGS':
return (
<ReviewCloudWatchDatasource
currentName={name}
currentDetails={details}
currentArn={arn}
currentStore={storeURI}
currentRegion={region}
selectedQueryPermissionRoles={selectedQueryPermissionRoles}
currentAuthMethod={authMethod}
goBack={() => setPage('configure')}
/>
);
default:
return <></>;
}
Expand Down Expand Up @@ -284,6 +329,34 @@ export function Configure(props: ConfigureDatasourceProps) {
}),
});
break;
case 'CLOUDWATCHLOGS':
const cloudWatchProperties =
authMethod === 'basicauth'
? {
'cloudwatchlog.auth.type': 'iam_role',
'cloudwatchlog.auth.role_arn': arn,
'cloudwatchlog.region': region,
'cloudwatchlog.indexstore.opensearch.uri': storeURI,
'cloudwatchlog.indexstore.opensearch.auth': authMethod,
'cloudwatchlog.indexstore.opensearch.auth.username': username,
'cloudwatchlog.indexstore.opensearch.auth.password': password,
}
: {
'cloudwatchlog.auth.type': 'iam_role',
'cloudwatchlog.auth.role_arn': arn,
'cloudwatchlog.region': region,
'cloudwatchlog.indexstore.opensearch.uri': storeURI,
'cloudwatchlog.indexstore.opensearch.auth': authMethod,
};
response = http!.post(`${DATACONNECTIONS_BASE}`, {
body: JSON.stringify({
name,
allowedRoles: selectedQueryPermissionRoles.map((role) => role.label),
connector: 'cloudwatchlog',
properties: cloudWatchProperties,
}),
});
break;
default:
response = Promise.reject('Invalid data source type');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
EuiFieldText,
EuiTextArea,
EuiSelect,
EuiFieldPassword,
EuiForm,
} from '@elastic/eui';
import React, { useState } from 'react';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React from 'react';
import { NewDatasourceDescription } from './new_datasource_description';
import s3Svg from '../../icons/s3-logo.svg';
import prometheusSvg from '../../icons/prometheus-logo.svg';
import cloudWatchSvg from '../../icons/amazon_cloudwatch-icon.svg';
import { DatasourceType } from '../../../../../common/types/data_connections';

export interface DatasourceCard {
Expand All @@ -34,6 +35,13 @@ export function NewDatasourceCardView() {
displayIcon: <EuiIcon type={prometheusSvg} size="xl" />,
onClick: () => (window.location.hash = `#/configure/PROMETHEUS`),
},
{
name: 'CLOUDWATCHLOGS',
displayName: 'Cloud Watch Logs',
description: 'Connect to CloudWatch Logs',
displayIcon: <EuiIcon type={cloudWatchSvg} size="xl" />,
onClick: () => (window.location.hash = `#/configure/CLOUDWATCHLOGS`),
},
];

const renderRows = (datasources: DatasourceCard[]) => {
Expand Down
Loading

0 comments on commit 6a7f80a

Please sign in to comment.