def _fn_snow_helper_update_datatable_function(self, event, *args, **kwargs):
        """Function: A helper function that updates the ServiceNow Records Data Table when the status of an Incident/Task is changed."""

        log = logging.getLogger(__name__)

        try:
            # Instansiate helper (which gets appconfigs from file)
            res_helper = ResilientHelper(self.options)

            # Get the function inputs:
            inputs = {
                "incident_id": res_helper.get_function_input(kwargs, "incident_id"),  # number (required)
                "task_id": res_helper.get_function_input(kwargs, "task_id", True),  # number (optional)
                "sn_resilient_status": res_helper.get_function_input(kwargs, "sn_resilient_status"),  # text (required)
            }

            # Create payload dict with inputs
            payload = FunctionPayload(inputs)

            yield StatusMessage("Function Inputs OK")

            # Instansiate new Resilient API object
            res_client = self.rest_client()

            # Instansiate a reference to the ServiceNow Datatable
            res_datatable = ServiceNowRecordsDataTable(res_client, payload.inputs["incident_id"])

            # Get the datatable data and rows
            res_datatable.get_data()

            # Generate the res_id
            payload.res_id = res_helper.generate_res_id(payload.inputs["incident_id"], payload.inputs["task_id"])

            # Search for a row that contains the res_id
            row_found = res_datatable.get_row("sn_records_dt_res_id", payload.res_id)

            # Get current time (*1000 as API does not accept int)
            now = int(time.time() * 1000)

            if row_found:

                resilient_status = res_helper.state_to_text(payload.inputs.get("sn_resilient_status"))

                yield StatusMessage("Row found for {0}. Updating resilient_status to {1}".format(
                    payload.res_id, resilient_status))

                if resilient_status == "Active":
                    resilient_status = res_helper.convert_text_to_richtext("Active", "green")

                else:
                    resilient_status = res_helper.convert_text_to_richtext("Closed", "red")

                cells_to_update = {
                    "sn_records_dt_time": now,
                    "sn_records_dt_res_status": resilient_status
                }

                # Update the row
                update_row_response = res_datatable.update_row(row_found, cells_to_update)
                payload.row_id = update_row_response["id"]

            else:
                payload.success = False
                err_msg = "No row found for the {0} {1}"

                if payload.inputs["task_id"]:
                    err_msg = err_msg.format("Task", payload.inputs["task_id"])

                else:
                    err_msg = err_msg.format("Incident", payload.inputs["incident_id"])

                yield StatusMessage(err_msg)

            results = payload.as_dict()

            log.debug("RESULTS: %s", results)
            log.info("Complete")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Exemplo n.º 2
0
    def _fn_snow_add_note_to_record_function(self, event, *args, **kwargs):
        """Function: Function that adds a Note to a ServiceNow Record. Option to add the note as a 'Work Note' or 'Additional Comment'."""

        log = logging.getLogger(__name__)

        try:
            # Instansiate helper (which gets appconfigs from file)
            res_helper = ResilientHelper(self.options)

            # Get the function inputs:
            inputs = {
                "incident_id": res_helper.get_function_input(kwargs, "incident_id"),  # number (required)
                "task_id": res_helper.get_function_input(kwargs, "task_id", True),  # number
                "sn_note_text": res_helper.get_function_input(kwargs, "sn_note_text"),  # text (required)
                "sn_note_type": res_helper.get_function_input(kwargs, "sn_note_type")["name"]  # select, text (required)
            }

            # Convert rich text comment to plain text
            soup = BeautifulSoup(inputs["sn_note_text"], 'html.parser')
            soup = soup.get_text()
            inputs["sn_note_text"] = soup.replace(u'\xa0', u' ')

            # Create payload dict with inputs
            payload = FunctionPayload(inputs)

            yield StatusMessage("Function Inputs OK")

            # Instansiate new Resilient API object
            res_client = self.rest_client()

            # Get the datatable
            datatable = ServiceNowRecordsDataTable(res_client, payload.inputs["incident_id"])

            # Generate res_id using incident and task id
            res_id = res_helper.generate_res_id(payload.inputs["incident_id"], payload.inputs["task_id"])

            # Get the sn_ref_id
            sn_ref_id = datatable.get_sn_ref_id(res_id)

            if not sn_ref_id:
                payload.success = False
                err_msg = "Failed to add Note. This {0} has not been created in ServiceNow yet. {0} ID: {1}"

                if payload.inputs["task_id"]:
                    err_msg = err_msg.format("Task", payload.inputs["task_id"])

                else:
                    err_msg = err_msg.format("Incident", payload.inputs["incident_id"])

                raise ValueError(err_msg)

            else:
                # Generate the request_data
                request_data = {
                    "sn_ref_id": sn_ref_id,
                    "sn_table_name": res_helper.SN_TABLE_NAME,
                    "type": "comment",
                    "sn_note_text": payload.inputs["sn_note_text"],
                    "sn_note_type": payload.inputs["sn_note_type"]
                }

                yield StatusMessage("Adding Note to ServiceNow Record {0}".format(sn_ref_id))

                # Call POST and get response
                add_in_sn_response = res_helper.sn_api_request("POST", "/add", data=json.dumps(request_data))
                payload.res_id = res_id
                payload.sn_ref_id = add_in_sn_response["sn_ref_id"]

            results = payload.as_dict()
            log.debug("RESULTS: %s", results)

            log.info("Complete")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _fn_snow_update_record_function(self, event, *args, **kwargs):
        """Function: Function that uses the '/update' custom endpoint in ServiceNow to update a ServiceNow Record with a given dictionary of field name/value pairs."""

        log = logging.getLogger(__name__)

        try:
            # Instansiate helper (which gets appconfigs from file)
            res_helper = ResilientHelper(self.options)

            # Get the function inputs:
            inputs = {
                "incident_id":
                res_helper.get_function_input(
                    kwargs, "incident_id"),  # number (required)
                "task_id":
                res_helper.get_function_input(kwargs, "task_id",
                                              True),  # number (optional)
                "sn_res_id":
                res_helper.get_function_input(kwargs, "sn_res_id",
                                              True),  # text (optional)
                "sn_update_fields":
                res_helper.get_function_input(
                    kwargs, "sn_update_fields")  # text, JSON String (required)
            }

            # Convert 'sn_update_fields' JSON string to Dictionary
            try:
                inputs["sn_update_fields"] = json.loads(
                    inputs.get("sn_update_fields"),
                    object_hook=res_helper._byteify)
            except Exception:
                raise ValueError(
                    "sn_update_fields JSON String is invalid: {0}".format(
                        inputs.get("sn_update_fields")))

            # Create payload dict with inputs
            payload = FunctionPayload(inputs)

            yield StatusMessage("Function Inputs OK")

            # Instansiate new Resilient API object
            res_client = self.rest_client()

            sn_ref_id = payload.inputs.get("sn_ref_id")

            if sn_ref_id is None:

                # Generate res_id using incident and task id
                res_id = res_helper.generate_res_id(
                    payload.inputs.get("incident_id"),
                    payload.inputs.get("task_id"))

                # Instansiate a reference to the ServiceNow Datatable
                datatable = ServiceNowRecordsDataTable(
                    res_client, payload.inputs.get("incident_id"))

                # Get the sn_ref_id
                sn_ref_id = datatable.get_sn_ref_id(res_id)

                if sn_ref_id is None:
                    payload.success = False
                    err_msg = "Failed to update a ServiceNow Record. This {0} has not been created in ServiceNow yet. {0} ID: {1}"

                    if payload.inputs["task_id"]:
                        err_msg = err_msg.format("Task",
                                                 payload.inputs.get("task_id"))

                    else:
                        err_msg = err_msg.format(
                            "Incident", payload.inputs.get("incident_id"))

                    raise ValueError(err_msg)

            yield StatusMessage(
                "Updating ServiceNow Record {0}".format(sn_ref_id))

            # Get sn_update_fields
            sn_update_fields = payload.inputs.get("sn_update_fields")

            # Initialize list for request_data
            fields = []

            # Loop fields and format for request
            for field_name in sn_update_fields:
                field_value = sn_update_fields[field_name]
                fields.append({
                    "name": field_name,
                    "value": sn_update_fields[field_name]
                })
                yield StatusMessage("Updating {0} to {1}".format(
                    field_name, field_value))

            request_data = {
                "sn_ref_id": sn_ref_id,
                "sn_table_name": res_helper.SN_TABLE_NAME,
                "sn_update_fields": fields
            }

            # Call PATCH and get response
            update_response = res_helper.sn_api_request(
                "PATCH", "/update", data=json.dumps(request_data))
            payload.sn_ref_id = update_response.get("sn_ref_id")
            payload.sn_time_updated = int(
                time.time() *
                1000)  # Get current time (*1000 as API does not accept int)

            results = payload.as_dict()
            log.debug("RESULTS: %s", results)
            log.info("Complete")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
    def _fn_snow_close_record_function(self, event, *args, **kwargs):
        """Function: Function that uses the '/close_record' custom endpoint in ServiceNow to change the state of a ServiceNow Record and add Close Notes and a Close Code to the Record."""

        err_msg = None

        log = logging.getLogger(__name__)

        try:
            # Instansiate helper (which gets appconfigs from file)
            res_helper = ResilientHelper(self.options)

            # Get the function inputs:
            inputs = {
                "incident_id": res_helper.get_function_input(kwargs, "incident_id"),  # number (required)
                "task_id": res_helper.get_function_input(kwargs, "task_id", True),  # number (optional)
                "sn_res_id": res_helper.get_function_input(kwargs, "sn_res_id", True),  # number (optional)
                "sn_record_state": res_helper.get_function_input(kwargs, "sn_record_state"),  # number (required)
                "sn_close_notes": res_helper.get_function_input(kwargs, "sn_close_notes"),  # text (required)
                "sn_close_code": res_helper.get_function_input(kwargs, "sn_close_code"),  # text (required)
                "sn_close_work_note": res_helper.get_function_input(kwargs, "sn_close_work_note", True),  # text (optional)
            }

            # Create payload dict with inputs
            payload = FunctionPayload(inputs)

            yield StatusMessage("Function Inputs OK")

            # Instansiate new Resilient API object
            res_client = self.rest_client()

            # Get the datatable and its data
            datatable = ServiceNowRecordsDataTable(res_client, payload.inputs["incident_id"])

            # Generate the res_id
            res_id = res_helper.generate_res_id(payload.inputs["incident_id"], payload.inputs["task_id"], payload.inputs["sn_res_id"])

            # Get the sn_ref_id
            sn_ref_id = datatable.get_sn_ref_id(res_id)

            if not sn_ref_id:
                err_msg = "Failed to close this {0} in ServiceNow. This {0} has not been created in ServiceNow yet. {0} ID: {1}"

                if payload.inputs["task_id"]:
                    err_msg = err_msg.format("Task", payload.inputs["task_id"])

                else:
                    err_msg = err_msg.format("Incident", payload.inputs["incident_id"])

                payload.success = False
                payload.reason = err_msg
                yield StatusMessage(err_msg)

            else:
                # Generate the request_data
                request_data = {
                    "sn_ref_id": sn_ref_id,
                    "sn_table_name": res_helper.SN_TABLE_NAME,
                    "sn_close_code": payload.inputs["sn_close_code"],
                    "sn_close_notes": payload.inputs["sn_close_notes"],
                    "sn_record_state": payload.inputs["sn_record_state"],
                    "sn_close_work_note": payload.inputs["sn_close_work_note"]
                }

                try:
                    yield StatusMessage("Closing ServiceNow Record {0}".format(sn_ref_id))
                    close_in_sn_response = res_helper.sn_api_request("POST", "/close_record", data=json.dumps(request_data))
                    payload.sn_ref_id = sn_ref_id
                    payload.sn_record_state = close_in_sn_response["sn_state"]

                    try:
                        yield StatusMessage("Updating ServiceNow Records Data Table Status to {0}".format(close_in_sn_response["sn_state"]))

                        row_to_update = datatable.get_row("sn_records_dt_sn_ref_id", sn_ref_id)

                        cells_to_update = {
                            "sn_records_dt_time": int(time.time() * 1000),
                            "sn_records_dt_snow_status": res_helper.convert_text_to_richtext(close_in_sn_response["sn_state"], "red")
                        }

                        # Update the row
                        datatable.update_row(row_to_update, cells_to_update)

                    except Exception as err:
                        payload.success = False
                        raise ValueError("Failed to update ServiceNow Status in Datatable: {0}".format(err))

                except Exception as err:
                    err_msg = "Failed to close ServiceNow Record {0}".format(err)
                    payload.success = False
                    payload.reason = err_msg
                    yield StatusMessage(err_msg)

            results = payload.as_dict()
            log.debug("RESULTS: %s", results)
            log.info("Complete")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Exemplo n.º 5
0
    def _fn_snow_add_attachment_to_record_function(self, event, *args, **kwargs):
        """Function: Function that adds a Resilient Attachment to a ServiceNow Record."""

        log = logging.getLogger(__name__)

        try:
            # Instansiate helper (which gets appconfigs from file)
            res_helper = ResilientHelper(self.options)

            # Get the function inputs:
            inputs = {
                "attachment_id": res_helper.get_function_input(kwargs, "attachment_id"),  # number (required)
                "incident_id": res_helper.get_function_input(kwargs, "incident_id"),  # number (required)
                "task_id": res_helper.get_function_input(kwargs, "task_id", True)  # number (optional)
            }

            # Create payload dict with inputs
            payload = FunctionPayload(inputs)

            yield StatusMessage("Function Inputs OK")

            # Instansiate new Resilient API object
            res_client = self.rest_client()

            yield StatusMessage("Getting attachment data. ID: {0}".format(payload.inputs["attachment_id"]))

            # Get the attachment
            attachment = res_helper.get_attachment(res_client,
                                                   payload.inputs["attachment_id"],
                                                   payload.inputs["incident_id"],
                                                   payload.inputs["task_id"])

            # Get the datatable
            datatable = ServiceNowRecordsDataTable(res_client, payload.inputs["incident_id"])

            # Generate res_id using incident and task id
            res_id = res_helper.generate_res_id(payload.inputs["incident_id"], payload.inputs["task_id"])

            # Get the sn_ref_id from the datatable
            sn_ref_id = datatable.get_sn_ref_id(res_id)

            if not sn_ref_id:
                payload.success = False
                err_msg = "Failed to add Attachment to ServiceNow. This {0} has not been created in ServiceNow yet. {0} ID: {1}"

                if payload.inputs["task_id"]:
                    err_msg = err_msg.format("Task", payload.inputs["task_id"])

                else:
                    err_msg = err_msg.format("Incident", payload.inputs["incident_id"])

                raise ValueError(err_msg)

            else:
                # Generate the request_data
                request_data = {
                    "sn_ref_id": sn_ref_id,
                    "sn_table_name": res_helper.SN_TABLE_NAME,
                    "type": "attachment",
                    "attachment_base64": attachment["contents"],
                    "attachment_name": attachment["name"],
                    "attachment_content_type": attachment["content_type"]
                }

                yield StatusMessage("Adding Attachment to ServiceNow Record {0}".format(sn_ref_id))

                # Call POST and get response
                add_in_sn_response = res_helper.sn_api_request("POST", "/add", data=json.dumps(request_data))
                payload.res_id = res_id
                payload.sn_ref_id = sn_ref_id
                payload.attachment_name = attachment["name"]
                payload.sn_attachment_sys_id = add_in_sn_response["attachment_id"]

            results = payload.as_dict()

            log.info("Complete")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()