Skip to content

Commit

Permalink
Add conditional installation for S3 integrations (#1518)
Browse files Browse the repository at this point in the history
* Add workflows to integration format

Signed-off-by: Simeon Widdis <[email protected]>

* Render integration workflows on frontend

Signed-off-by: Simeon Widdis <[email protected]>

* Add ability to toggle workflows to frontend

Signed-off-by: Simeon Widdis <[email protected]>

* Add workflows to integration build options

Signed-off-by: Simeon Widdis <[email protected]>

* Add asset workflow filtering to builder

Signed-off-by: Simeon Widdis <[email protected]>

* Add enabled workflows to setup request

Signed-off-by: Simeon Widdis <[email protected]>

* Don't allow integration setup if no workflows enabled

Signed-off-by: Simeon Widdis <[email protected]>

* Add workflows to other integrations

Signed-off-by: Simeon Widdis <[email protected]>

* Improve header for workflows section

Signed-off-by: Simeon Widdis <[email protected]>

* Update snapshots

Signed-off-by: Simeon Widdis <[email protected]>

---------

Signed-off-by: Simeon Widdis <[email protected]>
(cherry picked from commit 8874c8c)
Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
github-actions[bot] committed Mar 13, 2024
1 parent 2d18a4f commit 66cfc55
Show file tree
Hide file tree
Showing 16 changed files with 1,579 additions and 51 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,19 @@ describe('Integration Setup Page', () => {
expect(wrapper).toMatchSnapshot();
});
});

it('Renders the S3 connector form without workflows', async () => {
const wrapper = mount(
<SetupIntegrationForm
config={{ ...TEST_INTEGRATION_SETUP_INPUTS, connectionType: 's3' }}
updateConfig={() => {}}
integration={{ ...TEST_INTEGRATION_CONFIG, workflows: undefined }}
setupCallout={{ show: false }}
/>
);

await waitFor(() => {
expect(wrapper).toMatchSnapshot();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ export async function addIntegrationRequest(
integration: IntegrationConfig,
setToast: (title: string, color?: Color, text?: string | undefined) => void,
name?: string,
dataSource?: string
dataSource?: string,
workflows?: string[]
): Promise<boolean> {
const http = coreRefs.http!;
if (addSample) {
Expand All @@ -298,7 +299,7 @@ export async function addIntegrationRequest(

let response: boolean = await http
.post(`${INTEGRATIONS_BASE}/store/${templateName}`, {
body: JSON.stringify({ name, dataSource }),
body: JSON.stringify({ name, dataSource, workflows }),
})
.then((res) => {
setToast(`${name} integration successfully added!`, 'success');
Expand Down
120 changes: 105 additions & 15 deletions public/components/integrations/components/setup_integration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
EuiButton,
EuiButtonEmpty,
EuiCallOut,
EuiCheckableCard,
EuiComboBox,
EuiEmptyPrompt,
EuiFieldText,
Expand Down Expand Up @@ -42,6 +43,7 @@ export interface IntegrationSetupInputs {
connectionLocation: string;
checkpointLocation: string;
connectionTableName: string;
enabledWorkflows: string[];
}

type SetupCallout = { show: true; title: string; color?: Color; text?: string } | { show: false };
Expand Down Expand Up @@ -182,6 +184,38 @@ const runQuery = async (
}
};

export function SetupWorkflowSelector({
integration,
useWorkflows,
toggleWorkflow,
}: {
integration: IntegrationConfig;
useWorkflows: Map<string, boolean>;
toggleWorkflow: (name: string) => void;
}) {
if (!integration.workflows) {
return null;

Check warning on line 197 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L197

Added line #L197 was not covered by tests
}

const cards = integration.workflows.map((workflow) => {
return (
<EuiCheckableCard
id={`workflow-checkbox-${workflow.name}`}
key={workflow.name}
label={workflow.label}
checkableType="checkbox"
value={workflow.name}
checked={useWorkflows.get(workflow.name)}
onChange={() => toggleWorkflow(workflow.name)}

Check warning on line 209 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L209

Added line #L209 was not covered by tests
>
{workflow.description}
</EuiCheckableCard>
);
});

return cards;
}

export function SetupIntegrationForm({
config,
updateConfig,
Expand All @@ -197,6 +231,25 @@ export function SetupIntegrationForm({
const [isBucketBlurred, setIsBucketBlurred] = useState(false);
const [isCheckpointBlurred, setIsCheckpointBlurred] = useState(false);

const [useWorkflows, setUseWorkflows] = useState(new Map<string, boolean>());
const toggleWorkflow = (name: string) => {
setUseWorkflows(new Map(useWorkflows.set(name, !useWorkflows.get(name))));

Check warning on line 236 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L236

Added line #L236 was not covered by tests
};

useEffect(() => {
if (integration.workflows) {
setUseWorkflows(new Map(integration.workflows.map((w) => [w.name, w.enabled_by_default])));
}
}, [integration.workflows]);

useEffect(() => {
updateConfig({
enabledWorkflows: [...useWorkflows.entries()].filter((w) => w[1]).map((w) => w[0]),
});
// If we add the updateConfig dep here, rendering crashes with "Maximum update depth exceeded"
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [useWorkflows]);

useEffect(() => {
const updateDataSources = async () => {
const data = await suggestDataSources(config.connectionType);
Expand Down Expand Up @@ -339,12 +392,47 @@ export function SetupIntegrationForm({
}}
/>
</EuiFormRow>
{integration.workflows ? (
<>
<EuiSpacer />
<EuiText>
<h3>Installation Flows</h3>
</EuiText>
<EuiSpacer />
<EuiFormRow
label={'Flows'}
helpText={
'Select from the available asset types based on your use case. Choose at least one.'
}
isInvalid={![...useWorkflows.values()].includes(true)}
error={['Must select at least one workflow.']}
>
<SetupWorkflowSelector
integration={integration}
useWorkflows={useWorkflows}
toggleWorkflow={toggleWorkflow}
/>
</EuiFormRow>
</>
) : null}
</>
) : null}
</EuiForm>
);
}

const prepareQuery = (query: string, config: IntegrationSetupInputs): string => {
let queryStr = query.replaceAll(

Check warning on line 425 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L425

Added line #L425 was not covered by tests
'{table_name}',
`${config.connectionDataSource}.default.${config.connectionTableName}`
);
queryStr = queryStr.replaceAll('{s3_bucket_location}', config.connectionLocation);
queryStr = queryStr.replaceAll('{s3_checkpoint_location}', config.checkpointLocation);
queryStr = queryStr.replaceAll('{object_name}', config.connectionTableName);
queryStr = queryStr.replaceAll(/\s+/g, ' ');
return queryStr;

Check warning on line 433 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L429-L433

Added lines #L429 - L433 were not covered by tests
};

const addIntegration = async ({
config,
integration,
Expand Down Expand Up @@ -375,22 +463,20 @@ const addIntegration = async ({
} else if (config.connectionType === 's3') {
const http = coreRefs.http!;

const assets = await http.get(`${INTEGRATIONS_BASE}/repository/${integration.name}/assets`);
const assets: { data: ParsedIntegrationAsset[] } = await http.get(

Check warning on line 466 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L466

Added line #L466 was not covered by tests
`${INTEGRATIONS_BASE}/repository/${integration.name}/assets`
);

// Queries must exist because we disable s3 if they're not present
for (const query of assets.data.filter(
(a: ParsedIntegrationAsset): a is { type: 'query'; query: string; language: string } =>
(a: ParsedIntegrationAsset): a is ParsedIntegrationAsset & { type: 'query' } =>
a.type === 'query'
)) {
let queryStr = (query.query as string).replaceAll(
'{table_name}',
`${config.connectionDataSource}.default.${config.connectionTableName}`
);
// Skip any queries that have conditional workflows but aren't enabled
if (query.workflows && !query.workflows.some((w) => config.enabledWorkflows.includes(w))) {
continue;

Check warning on line 476 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L476

Added line #L476 was not covered by tests
}

queryStr = queryStr.replaceAll('{s3_bucket_location}', config.connectionLocation);
queryStr = queryStr.replaceAll('{s3_checkpoint_location}', config.checkpointLocation);
queryStr = queryStr.replaceAll('{object_name}', config.connectionTableName);
queryStr = queryStr.replaceAll(/\s+/g, ' ');
const queryStr = prepareQuery(query.query, config);

Check warning on line 479 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L479

Added line #L479 was not covered by tests
const result = await runQuery(queryStr, config.connectionDataSource, sessionId);
if (!result.ok) {
setLoading(false);
Expand All @@ -400,15 +486,15 @@ const addIntegration = async ({
sessionId = result.value.sessionId ?? sessionId;
}
// Once everything is ready, add the integration to the new datasource as usual
// TODO determine actual values here after more about queries is known
const res = await addIntegrationRequest(
false,
integration.name,
config.displayName,
integration,
setCalloutLikeToast,
config.displayName,
`flint_${config.connectionDataSource}_default_${config.connectionTableName}_mview`
`flint_${config.connectionDataSource}_default_${config.connectionTableName}_mview`,
config.enabledWorkflows
);
if (!res) {
setLoading(false);
Expand All @@ -418,11 +504,14 @@ const addIntegration = async ({
}
};

const isConfigValid = (config: IntegrationSetupInputs): boolean => {
const isConfigValid = (config: IntegrationSetupInputs, integration: IntegrationConfig): boolean => {
if (config.displayName.length < 1 || config.connectionDataSource.length < 1) {
return false;
}
if (config.connectionType === 's3') {
if (integration.workflows && config.enabledWorkflows.length < 1) {
return false;

Check warning on line 513 in public/components/integrations/components/setup_integration.tsx

View check run for this annotation

Codecov / codecov/patch

public/components/integrations/components/setup_integration.tsx#L513

Added line #L513 was not covered by tests
}
return (
config.connectionLocation.startsWith('s3://') && config.checkpointLocation.startsWith('s3://')
);
Expand Down Expand Up @@ -477,7 +566,7 @@ export function SetupBottomBar({
iconType="arrowRight"
iconSide="right"
isLoading={loading}
disabled={!isConfigValid(config)}
disabled={!isConfigValid(config, integration)}
onClick={async () =>
addIntegration({ integration, config, setLoading, setCalloutLikeToast })
}
Expand Down Expand Up @@ -511,6 +600,7 @@ export function SetupIntegrationPage({ integration }: { integration: string }) {
connectionLocation: '',
checkpointLocation: '',
connectionTableName: integration,
enabledWorkflows: [],
});

const [template, setTemplate] = useState({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@
"labels": ["Observability", "Logs", "AWS", "Flint S3", "Cloud"],
"author": "OpenSearch",
"sourceUrl": "https://github.com/opensearch-project/dashboards-observability/tree/main/server/adaptors/integrations/__data__/repository/aws_elb/info",
"workflows": [
{
"name": "queries",
"label": "Queries (recommended)",
"description": "Tables and pre-written queries for quickly getting insights on your data.",
"enabled_by_default": true
},
{
"name": "dashboards",
"label": "Dashboards & Visualizations",
"description": "Dashboards and indices that enable you to easily visualize important metrics.",
"enabled_by_default": false
}
],
"statics": {
"logo": {
"annotation": "ELB Logo",
Expand Down Expand Up @@ -51,7 +65,8 @@
"name": "aws_elb",
"version": "1.0.0",
"extension": "ndjson",
"type": "savedObjectBundle"
"type": "savedObjectBundle",
"workflows": ["dashboards"]
},
{
"name": "create_table",
Expand All @@ -63,7 +78,8 @@
"name": "create_mv",
"version": "1.0.0",
"extension": "sql",
"type": "query"
"type": "query",
"workflows": ["dashboards"]
}
],
"sampleData": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@
"labels": ["Observability", "Logs", "AWS", "Cloud", "Flint S3"],
"author": "Haidong Wang",
"sourceUrl": "https://github.com/opensearch-project/dashboards-observability/tree/main/server/adaptors/integrations/__data__/repository/aws_vpc_flow/info",
"workflows": [
{
"name": "queries",
"label": "Queries (recommended)",
"description": "Tables and pre-written queries for quickly getting insights on your data.",
"enabled_by_default": true
},
{
"name": "dashboards",
"label": "Dashboards & Visualizations",
"description": "Dashboards and indices that enable you to easily visualize important metrics.",
"enabled_by_default": false
}
],
"statics": {
"logo": {
"annotation": "AWS VPC Logo",
Expand Down Expand Up @@ -47,7 +61,8 @@
"name": "aws_vpc_flow",
"version": "1.0.0",
"extension": "ndjson",
"type": "savedObjectBundle"
"type": "savedObjectBundle",
"workflows": ["dashboards"]
},
{
"name": "create_table_vpc",
Expand All @@ -59,7 +74,8 @@
"name": "create_mv_vpc",
"version": "1.0.0",
"extension": "sql",
"type": "query"
"type": "query",
"workflows": ["dashboards"]
}
],
"sampleData": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@
"labels": ["Observability", "Logs", "Flint S3"],
"author": "OpenSearch",
"sourceUrl": "https://github.com/opensearch-project/dashboards-observability/tree/main/server/adaptors/integrations/__data__/repository/nginx/info",
"workflows": [
{
"name": "queries",
"label": "Queries (recommended)",
"description": "Tables and pre-written queries for quickly getting insights on your data.",
"enabled_by_default": true
},
{
"name": "dashboards",
"label": "Dashboards & Visualizations",
"description": "Dashboards and indices that enable you to easily visualize important metrics.",
"enabled_by_default": false
}
],
"statics": {
"logo": {
"annotation": "NginX Logo",
Expand Down Expand Up @@ -43,7 +57,8 @@
"name": "nginx",
"version": "1.0.0",
"extension": "ndjson",
"type": "savedObjectBundle"
"type": "savedObjectBundle",
"workflows": ["dashboards"]
},
{
"name": "create_table",
Expand All @@ -55,7 +70,8 @@
"name": "create_mv",
"version": "1.0.0",
"extension": "sql",
"type": "query"
"type": "query",
"workflows": ["dashboards"]
}
],
"sampleData": {
Expand Down
Loading

0 comments on commit 66cfc55

Please sign in to comment.