Repository navigation
HY/CRTX-287602/ServicenowEvents #46420
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
base: master
Are you sure you want to change the base?
Changes from all commits
a532498
fcab73f
cd2b1ea
128b390
ea71497
49baf24
ee95e8a
e466fb8
6af9690
1a360b9
af29b96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1271,6 +1271,23 @@ def create_co_from_template(self, template: str): | |||||||||||||||
| """ | ||||||||||||||||
| return self.send_request(f"change/standard/{template}", "POST", body={}, cr_api=True) | ||||||||||||||||
|
|
||||||||||||||||
| def create_event(self, events: list[dict]) -> dict: | ||||||||||||||||
| """Create one or more events in ServiceNow Event Management. | ||||||||||||||||
|
|
||||||||||||||||
| Sends events to the /api/global/em/jsonv2 webhook endpoint which writes | ||||||||||||||||
| to the em_events table. | ||||||||||||||||
|
|
||||||||||||||||
| Args: | ||||||||||||||||
| events: List of event dictionaries. Each event may contain fields | ||||||||||||||||
| such as source, node, type, resource, severity, description, | ||||||||||||||||
| time_of_event, and additional_info. | ||||||||||||||||
|
|
||||||||||||||||
| Returns: | ||||||||||||||||
| Response dict from ServiceNow. | ||||||||||||||||
| """ | ||||||||||||||||
| body = {"records": events} | ||||||||||||||||
| return self.send_request(path="", method="POST", body=body, custom_api="/api/global/em/jsonv2") | ||||||||||||||||
|
|
||||||||||||||||
| def get_co_tasks(self, sys_id: str) -> dict: | ||||||||||||||||
| """Get item details from service catalog by sending a GET request to the Change Request REST API. | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -3748,6 +3765,63 @@ def get_co_human_readable(ticket: dict, ticket_type: str, additional_fields: Ite | |||||||||||||||
| return item | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def create_event_command(client: Client, args: dict) -> CommandResults: | ||||||||||||||||
| """Create an event in ServiceNow Event Management via the /api/global/em/jsonv2 webhook. | ||||||||||||||||
|
|
||||||||||||||||
| Builds the event from named arguments. ``source`` defaults to ``"Cortex"``. | ||||||||||||||||
| ``node``, ``type``, and ``time_of_event`` are required. | ||||||||||||||||
|
|
||||||||||||||||
| Args: | ||||||||||||||||
| client: Authenticated ServiceNow client. | ||||||||||||||||
| args: Command arguments, usually ``demisto.args()``. | ||||||||||||||||
|
|
||||||||||||||||
| Returns: | ||||||||||||||||
| ``CommandResults`` with a human-readable success message and the raw ServiceNow response. | ||||||||||||||||
|
|
||||||||||||||||
| Raises: | ||||||||||||||||
| DemistoException: If required fields are missing. | ||||||||||||||||
| """ | ||||||||||||||||
| severity_map: dict[str, str] = { | ||||||||||||||||
| "critical": "1", | ||||||||||||||||
| "high": "2", | ||||||||||||||||
| "medium": "3", | ||||||||||||||||
| "low": "4", | ||||||||||||||||
| "info": "5", | ||||||||||||||||
| } | ||||||||||||||||
| resolution_state_map: dict[str, str] = { | ||||||||||||||||
| "new": "open", | ||||||||||||||||
| "in progress": "open", | ||||||||||||||||
| "resolved": "closed", | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| node = args.get("node") | ||||||||||||||||
| event_type = args.get("type") | ||||||||||||||||
| time_of_event = args.get("time_of_event") | ||||||||||||||||
|
|
||||||||||||||||
| event: dict = { | ||||||||||||||||
| "source": args.get("source") or "Cortex", | ||||||||||||||||
| "node": node, | ||||||||||||||||
| "type": event_type, | ||||||||||||||||
| "time_of_event": time_of_event, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| for field in ("resource", "description", "additional_info", "message_key"): | ||||||||||||||||
| if (value := args.get(field)) is not None: | ||||||||||||||||
| event[field] = value | ||||||||||||||||
|
|
||||||||||||||||
| if (severity := args.get("severity")) is not None: | ||||||||||||||||
| event["severity"] = severity_map.get(severity.lower(), severity) | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If Consider casting to
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| if (resolution_state := args.get("resolution_state")) is not None: | ||||||||||||||||
| event["resolution_state"] = resolution_state_map.get(resolution_state.lower(), resolution_state) | ||||||||||||||||
|
|
||||||||||||||||
| client.create_event([event]) | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The docstring states that Consider capturing the response and including it in
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| return CommandResults( | ||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please assign the response from response = client.create_event([event])
return CommandResults(
readable_output="Event successfully sent to ServiceNow Event Management.",
raw_response=response,
) |
||||||||||||||||
| readable_output="Event successfully sent to ServiceNow Event Management.", | ||||||||||||||||
| ) | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def generic_api_call_command(client: Client, args: dict) -> Union[str, CommandResults]: | ||||||||||||||||
| """make a call to ServiceNow api | ||||||||||||||||
| Args: | ||||||||||||||||
|
|
@@ -3969,6 +4043,10 @@ def main(): | |||||||||||||||
| demisto.results(get_ticket_command(client, args)) | ||||||||||||||||
| elif command == "servicenow-delete-ticket": | ||||||||||||||||
| return_results(delete_ticket_command(client, args)) | ||||||||||||||||
| elif command == "servicenow-create-event": | ||||||||||||||||
| return_results(create_event_command(client, args)) | ||||||||||||||||
| elif command == "servicenow-create-event-quick-action": | ||||||||||||||||
| return_results(create_event_command(client, args)) | ||||||||||||||||
| elif command == "servicenow-generic-api-call": | ||||||||||||||||
| return_results(generic_api_call_command(client, args)) | ||||||||||||||||
| elif command == "get-remote-data": | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -1757,6 +1757,45 @@ script: | |||||
| - contextPath: ServiceNow.Tasks.State | ||||||
| description: state of task. | ||||||
| type: Unknown | ||||||
| - arguments: | ||||||
| - defaultValue: Cortex | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
According to Cortex XSOAR YAML formatting standards, schema keys are case-sensitive and should use lowercase (e.g., |
||||||
| description: Source of the event. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Argument descriptions should follow the descriptive form starting with "The " and ending with a period (e.g., "The source of the event."). Please apply this convention across the other newly added argument descriptions as well. |
||||||
| name: source | ||||||
| - description: Node where the event occurred. | ||||||
| name: node | ||||||
| required: true | ||||||
| - description: Type of the event. | ||||||
| name: type | ||||||
| required: true | ||||||
| - description: 'Time the event occurred, in the format: YYYY-MM-DD HH:MM:SS (UTC).' | ||||||
| name: time_of_event | ||||||
| required: true | ||||||
| - description: Resource on the node that triggered the event. | ||||||
| name: resource | ||||||
| - auto: PREDEFINED | ||||||
| description: Severity of the event. | ||||||
| name: severity | ||||||
| predefined: | ||||||
| - critical | ||||||
| - high | ||||||
| - medium | ||||||
| - low | ||||||
| - info | ||||||
| - description: Description of the event. | ||||||
| name: description | ||||||
| - description: 'Additional key-value pairs to attach to the event, in the format: {"key": "value"}.' | ||||||
| name: additional_info | ||||||
| - description: Unique key used to deduplicate events. | ||||||
| name: message_key | ||||||
| - auto: PREDEFINED | ||||||
| description: Resolution state of the event. | ||||||
| name: resolution_state | ||||||
| predefined: | ||||||
| - new | ||||||
| - in progress | ||||||
| - resolved | ||||||
| description: Creates an event in ServiceNow Event Management. | ||||||
| name: servicenow-create-event | ||||||
| - arguments: | ||||||
| - auto: PREDEFINED | ||||||
| defaultValue: 'GET' | ||||||
|
|
@@ -2009,7 +2048,67 @@ script: | |||||
| - contextPath: ServiceNow.Ticket.CloseCode | ||||||
| description: Ticket close code. | ||||||
| type: string | ||||||
|
|
||||||
| - arguments: | ||||||
| - defaultValue: Cortex | ||||||
| description: Source of the event. Defaults to "Cortex". | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Since a default value is defined in the argument's |
||||||
| name: source | ||||||
| prettyname: Source | ||||||
| required: true | ||||||
| - description: Node (hostname or asset name) where the event occurred. | ||||||
| name: node | ||||||
| prettyname: Node | ||||||
| required: true | ||||||
| prettypredefined: | ||||||
| Issue Name: ${issue.name} | ||||||
| - description: Event type. | ||||||
| name: type | ||||||
| prettyname: Type | ||||||
| required: true | ||||||
| prettypredefined: | ||||||
| Category: ${issue.categoryname} | ||||||
| - description: Time the event occurred, in the format "YYYY-MM-DD HH:MM:SS" (UTC). | ||||||
| name: time_of_event | ||||||
| prettyname: Time of Event | ||||||
| required: true | ||||||
| prettypredefined: | ||||||
| Created: ${issue.created} | ||||||
| - description: Resource on the node that triggered the event. | ||||||
| name: resource | ||||||
| prettyname: Resource | ||||||
| prettypredefined: | ||||||
| Issue ID: ${issue.id} | ||||||
| - auto: PREDEFINED | ||||||
| description: Severity of the event. Accepts Cortex labels (critical, high, medium, low, info) or raw ServiceNow integers (0–5). | ||||||
| name: severity | ||||||
| prettyname: Severity | ||||||
| prettypredefined: | ||||||
| Severity: ${issue.severityStr} | ||||||
| - description: Human-readable description of the event. | ||||||
| name: description | ||||||
| prettyname: Description | ||||||
| prettypredefined: | ||||||
| Details: ${issue.details} | ||||||
| - description: Unique key used to deduplicate events. | ||||||
| name: message_key | ||||||
| prettyname: Message Key | ||||||
| prettypredefined: | ||||||
| Issue ID: ${issue.id} | ||||||
| - description: Resolution state. Accepts Cortex labels (new, in progress, resolved) or raw ServiceNow values. | ||||||
| name: resolution_state | ||||||
| prettyname: Resolution State | ||||||
| prettypredefined: | ||||||
| Resolution Status: ${issue.resolution_status} | ||||||
| - description: Additional key-value pairs as a JSON string. Includes the full issue as serialized JSON. | ||||||
| name: additional_info | ||||||
| prettyname: Additional Info | ||||||
| prettypredefined: | ||||||
| Full Issue: ${issue} | ||||||
| description: Creates an event in ServiceNow Event Management. | ||||||
| name: servicenow-create-event-quick-action | ||||||
| prettyname: Create ServiceNow Event | ||||||
| hidden: true | ||||||
| quickaction: true | ||||||
| outputs: [] | ||||||
| dockerimage: demisto/auth-utils:1.0.0.13053055 | ||||||
| isfetch: true | ||||||
| ismappable: true | ||||||
|
|
@@ -2018,7 +2117,6 @@ script: | |||||
| script: '' | ||||||
| subtype: python3 | ||||||
| type: python | ||||||
|
|
||||||
| supportsquickactions: true | ||||||
| fromversion: 5.0.0 | ||||||
| tests: | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,5 @@ | ||||||
| #### Integrations | ||||||
|
|
||||||
| ##### ServiceNow v2 | ||||||
|
|
||||||
| - Added the new **servicenow-create-event** command, which creates an event in ServiceNow Event Management. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Command names should be formatted in bold-italics (
Suggested change
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring specifies that
node,type, andtime_of_eventare required fields and that aDemistoExceptionis raised if any are missing, but the function does not validate their presence before constructing the event. If omitted,Nonevalues are sent to ServiceNow.Consider adding explicit validation: