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

[RHCLOUD-36086] Refactor Splunk integration actions to not use behavior group apis anymore #627

Merged
Show file tree
Hide file tree
Changes from all 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
188 changes: 41 additions & 147 deletions src/pages/Integrations/SplunkSetup/useSplunkSetup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/*
Steps:

1) [GET] Retrieve UUIDs of Notifications event types to link to this new Splunk endpoint

1) [POST] Create Integrations under /api/integrations/v1.0/endpoints with the payload:
{
"name": "Splunk Automation",
Expand All @@ -14,49 +16,22 @@ Steps:
"secret_token": "MYHEC_TOKEN",
"basic_authentication": {},
"extras": {}
}
}

2) Create behavior group under /api/notifications/v1.0/notifications/behaviorGroups with the payload:

{
"bundle_id":"35fd787b-a345-4fe8-a135-7773de15905e",
"display_name":"Splunk-automation"
}

3) [POST] Update behavior group under api/notifications/v1.0/notifications/behaviorGroups/{BEHAVIOR_GROUP_ID}/actions with the payload:

["8d8dca57-1834-48dd-b6ac-265c949c5e60"] <<-- Id of the integration

4) [PUT] Update eventType under /api/notifications/v1.0/notifications/eventTypes/{EVENT_TYPE_UUID}/behaviorGroups with the payload:

["ff59b502-da25-4297-bd88-6934ad0e0d63"] <<- Behavior group ID
},
"event_types": ["3fa85f64-5717-4562-b3fc-2c963f66afa6","8d8dca57-1834-48dd-b6ac-265c949c5e60"] <<-- Event type Ids
*/

import { useClient } from 'react-fetching-library';

import { useGetAllEventTypes } from '../../../services/GetEventTypes';
import { useGetAnyBehaviorGroupByNotification } from '../../../services/Notifications/GetBehaviorGroupByNotificationId';
import { useGetBundleByName } from '../../../services/Notifications/GetBundles';
import { linkBehaviorGroupAction } from '../../../services/Notifications/LinkBehaviorGroup';
import { useSaveBehaviorGroupMutation } from '../../../services/Notifications/SaveBehaviorGroup';
import { useUpdateBehaviorGroupActionsMutation } from '../../../services/Notifications/UpdateBehaviorGroupActions';
import { useSaveIntegrationMutation } from '../../../services/useSaveIntegration';
import {
Integration,
IntegrationCamel,
IntegrationType,
NewIntegrationTemplate,
} from '../../../types/Integration';
import {
BehaviorGroup,
BehaviorGroupRequest,
UUID,
} from '../../../types/Notification';
import { UUID } from '../../../types/Notification';
import { useGetBundleByName } from '../../../services/Notifications/GetBundles';

export const SPLUNK_GROUP_NAME = 'SPLUNK_INTEGRATION';
export const SPLUNK_INTEGRATION_NAME = 'SPLUNK_AUTOMATION';
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove the SPLUNK_BEHAVIOR_GROUP_NAME constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

export const SPLUNK_BEHAVIOR_GROUP_NAME = 'SPLUNK_AUTOMATION_GROUP';
export const BUNDLE_NAME = 'rhel';

interface SplunkEventsDef {
Expand All @@ -74,52 +49,57 @@ const DEFAULT_SPLUNK_EVENTS: SplunkEventsDef = {
};

export const useSplunkSetup = () => {
const getRhelBundleUuid = useGetRhelBundleUuid();
const createSplunkIntegration = useCreateSplunkIntegration();
const createSplunkBehaviorGroup = useCreateSplunkBehaviorGroup();
const updateSplunkBehaviorActions = useUpdateSplunkBehaviorActions();
const attachEvents = useAttachEventsToSplunk();
const attachEventTypes = useFindEventTypesToAssociate();

return async ({ hecToken, splunkServerHostName }, onProgress) => {
const now = new Date();
const timestamp = now.getTime();
const integrationName = `${SPLUNK_INTEGRATION_NAME}_${timestamp}`;
const behaviorGroupName = `${SPLUNK_BEHAVIOR_GROUP_NAME}_${timestamp}`;
const bundleName = BUNDLE_NAME;
const events = DEFAULT_SPLUNK_EVENTS;

onProgress(`Fetching Event types...\n`);

const rhelBundleId = await getRhelBundleUuid();

const eventTypeList = await attachEventTypes(
rhelBundleId,
events,
onProgress
);

onProgress(`Creating Integration ${integrationName}...`);
const integration = await createSplunkIntegration({
await createSplunkIntegration({
integrationName,
hecToken,
splunkServerHostName,
eventTypeList,
});
onProgress(' OK', 'pf-v5-u-success-color-200');

onProgress(`\nCreating Behavior Group ${behaviorGroupName}...`);
const behaviorGroup = await createSplunkBehaviorGroup({
behaviorGroupName,
bundleName,
});
onProgress(' OK', 'pf-v5-u-success-color-200');

onProgress(
'\nAssociating integration as an action for the behavior group...'
);
await updateSplunkBehaviorActions(behaviorGroup, integration);
};
};

onProgress(' OK', 'pf-v5-u-success-color-200');
onProgress('\n\nAssociating events to the behavior group:\n');
const useGetRhelBundleUuid = () => {
const getBundleByName = useGetBundleByName();
return async () => {
const rhelBundle = await getBundleByName(BUNDLE_NAME);

await attachEvents(behaviorGroup, events, onProgress);
if (rhelBundle !== undefined) {
return rhelBundle?.id;
} else {
throw new Error(`Error when fetching bundle ${BUNDLE_NAME}`);
}
};
};

const useCreateSplunkIntegration = () => {
const { mutate } = useSaveIntegrationMutation();

return async ({
integrationName,
splunkServerHostName,
hecToken,
eventTypeList,
}): Promise<Integration | undefined> => {
const newIntegration: NewIntegrationTemplate<IntegrationCamel> = {
type: IntegrationType.SPLUNK,
Expand All @@ -128,6 +108,7 @@ const useCreateSplunkIntegration = () => {
secretToken: hecToken,
isEnabled: true,
sslVerificationEnabled: true,
eventTypes: eventTypeList,
};

const { payload, error, errorObject } = await mutate(newIntegration);
Expand All @@ -143,100 +124,17 @@ const useCreateSplunkIntegration = () => {
};
};

const useCreateSplunkBehaviorGroup = () => {
const { mutate } = useSaveBehaviorGroupMutation();
const getBundleByName = useGetBundleByName();

return async ({ behaviorGroupName, bundleName }): Promise<BehaviorGroup> => {
const bundle = await getBundleByName(bundleName);
if (!bundle) {
throw new Error(`Unable to find bundle ${bundleName}`);
}

const behaviorGroup: BehaviorGroupRequest = {
bundleId: bundle.id as UUID,
displayName: behaviorGroupName,
actions: [], // ignored
events: [], // ignored
};

const { payload, error, errorObject } = await mutate(behaviorGroup);
if (errorObject) {
throw errorObject;
}

if (error) {
throw new Error(
`Error when creating behavior group ${behaviorGroupName}`
);
}

return payload?.value as BehaviorGroup;
};
};

const useUpdateSplunkBehaviorActions = () => {
const { mutate } = useUpdateBehaviorGroupActionsMutation();
return async (behaviorGroup, integration) => {
const endpointIds = behaviorGroup.actions || [];
endpointIds.push(integration.id);

const params = {
behaviorGroupId: behaviorGroup.id,
endpointIds,
};
const { payload, error, errorObject } = await mutate(params);
if (errorObject) {
throw errorObject;
}

if (error) {
throw new Error(
`Error when linking behavior group ${behaviorGroup.id}` +
` with integration ${integration.id}`
);
}

return payload?.value;
};
};

const useAttachEventsToSplunk = () => {
const useFindEventTypesToAssociate = () => {
const getAllEventTypes = useGetAllEventTypes();
const client = useClient();
const getAnyBehaviorGroupByNotification =
useGetAnyBehaviorGroupByNotification();

const appendActionToNotification = async (eventType, behaviorGroup) => {
const existingActions = await getAnyBehaviorGroupByNotification(
eventType.id as UUID
);
const existingActionIds = existingActions.value as UUID[];
const newActionIds = [...existingActionIds, behaviorGroup.id];

const { payload, errorObject, error } = await client.query(
linkBehaviorGroupAction(eventType.id, newActionIds)
);
if (errorObject) {
throw errorObject;
}

if (error) {
throw new Error(`Unsuccessful linking of event type ${eventType.id}`);
}

return payload;
};

return async (behaviorGroup, events, onProgress) => {
return async (rhelBundleId, events, onProgress) => {
const eventTypes = await getAllEventTypes();

const selectedEventTypes = eventTypes.filter((eventType) => {
if (!eventType?.application) {
return false;
}

if (eventType.application.bundle_id !== behaviorGroup.bundleId) {
if (eventType.application.bundle_id !== rhelBundleId) {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

This part limited the event types to be part of a single bundle (RHEL/Insights). With this removal, this would attach events that match the name across all bundles. For example, Ansible has events not only for RHEL but also for OpenShift. Please update the event types selection to filter the bundle.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right, thank you, I updated it.

}

Expand All @@ -251,17 +149,13 @@ const useAttachEventsToSplunk = () => {
return true;
});

const selectedEventTypeIds: UUID[] = [];
for (const eventType of selectedEventTypes) {
onProgress(
` ${eventType.application?.display_name} - ${eventType.display_name}...`
` ${eventType.application?.display_name} - ${eventType.display_name}\n`
);
try {
await appendActionToNotification(eventType, behaviorGroup);
onProgress(' ASSOCIATED\n', 'pf-v5-u-success-color-200');
} catch (error) {
onProgress(' ERROR!\n', 'pf-v5-u-danger-color-200');
console.log(error);
}
selectedEventTypeIds.push(eventType.id as UUID);
}
return selectedEventTypeIds;
};
};
1 change: 1 addition & 0 deletions src/schemas/Integrations/Integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const IntegrationSchemaBase: Yup.SchemaOf<NewIntegrationBase> =
.oneOf(Object.values(Schemas.EndpointStatus.Enum))
.default(Schemas.EndpointStatus.Enum.UNKNOWN),
serverErrors: Yup.number().default(0),
eventTypes: Yup.array().of(Yup.string()).optional(),
});

export const IntegrationHttpSchema: Yup.SchemaOf<
Expand Down
1 change: 1 addition & 0 deletions src/types/Integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface IntegrationBase<T extends IntegrationType> {
isEnabled: boolean;
status?: Schemas.EndpointStatus | undefined;
serverErrors: number;
eventTypes?: Array<string> | undefined;
}

export interface IntegrationHttp
Expand Down
1 change: 1 addition & 0 deletions src/types/adapters/IntegrationAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,5 +282,6 @@ export const toServerIntegrationRequest = (
sub_type: subType,
description: '',
properties: toIntegrationProperties(integration),
event_types: integration.eventTypes,
};
};
Loading