Thank you for your feedback.
Form temporarily unavailable. Please try again or contact docfeedback@servicenow.com to submit your comments.
Versions
  • London
  • Kingston
  • Jakarta
  • Istanbul
  • Helsinki
  • Geneva
  • Store
Close

Create a custom pull bi-directional connector

Create a custom pull bi-directional connector

Create a bi-directional connector definition to send changes made to an alert back to the external event source.

Before you begin

Role required: evt_mgmt_admin

About this task

Currently, the SCOM connector is the only connector with bi-directional functionality by default. However, you can customize any connector to have bi-directional functionality.
When a connector definition is created, the boilerplate code that it contains is for the exchange of values from the external event source to the ServiceNow instance. Implement bi-directional functionality as one of these options:
  • Connector with full abilities, where there is an exchange of values to-and-from the external event source and the ServiceNow instance. Do this implementation by adding the updateSource method to the connector code.
  • A pull connector with bi-directional functionality. In a case where events are pushed to the ServiceNow instance from the event source (such as using REST or SNMP), the connector must contain an implementation only for forwarding updates back to the event source. Do this implementation by replacing the connector boilerplate code with the code sample in this document.
Note: Users must have write permission to the external source to provide the bi-directional functionality.

The MID Server can update any connector when manual changes to alerts are received, as depicted in this diagram.

Procedure

  1. Navigate to Event Management > Event Connectors (Pull) > Connector Definitions and click New.
  2. In the Connector Definition form, select the Bi-directional option. When the connector instance is configured as bi-directional, each manual update of an alert from this source instance is logged in the Update Queue table (em_connector_update_queue).
  3. In the Alert field identifier field, specify the alert field that contains the identifier used to associate the ServiceNow alert with the corresponding event or alert in the external event source. This identifier must be an actual alert field, not a field in the Additional information of the alert. To include a field that is contained only in the Additional information field, see Custom alert fields.
    • The Update queue business rule on the Alert table identifies each manual update of the alert and updates the connector queue with these changes. By default, changes to all alert fields are tracked.
    • The Event Management - Queue connector processor schedule job dequeues alert changes and sends them to the MID Server. By default, this dequeue process is performed in batches of 1,000 alerts. You can configure this batch size using the evt_mgmt.max_update_source_records property.
  4. In the connector JavaScript, specify the information required for the updateSource function. This function receives the manual changes from alerts and sends them to the external source, according to the source instance. Use this updateSource function to handle and parse all the alert fields that should be updated in the external source.
  5. After adding the update source method, update the test connection method.
    Note: When adding bi-directional functionality for a Push connector, the Connector Instance name must match the Source Instance field of the alerts generated by that event source.

    For an example of a connector script with full connector abilities, see the SCOM connector script that is provided with the base instance.

    To match alerts to the specific connector instance in the following example, the manual update of the alert is sent to the correct connector instance by matching the source instance name.

    When using the updateSource method, specify which fields you are looking to find and send to the source. In this code, you can find an example of Incident and State fields. Whenever a new incident is associated to the alert or the state of the alert is being changed manually, an update is sent to the external source monitor. External server users must have write permission to the external source to provide the bi-directional functionality. The following script example is of a new custom connector with bi-directional ability only, without retrieving events. The execute method must still appear in the script, but it is an implementation that returns success without performing any action.

    var ConnectorJS = Class.create();
    
    var SUCCESS = Packages.com.service_now.mid.probe.tpcon.OperationStatusType.SUCCESS;
    var FAILURE = Packages.com.service_now.mid.probe.tpcon.OperationStatusType.FAILURE;
    var Event   = Packages.com.snc.commons.eventmgmt.Event;
    var SNEventSenderProvider = Packages.com.service_now.mid.probe.event.SNEventSenderProvider;
    var HTTPRequest = Packages.com.glide.communications.HTTPRequest;
    
    var errorMessage = "";
    
    ConnectorJS.prototype = Object.extendsObject(AProbe, {
    	
    	// test the connection with the target monitor
    	testConnection : function() {
    		
    		ms.log("Connector testing connection");
    		
    		var retVal = {};
    		
    		try {
    			
    			//TODO: run test query
    			
    			if (true){ //TODO: validate the request response
    				retVal['status']  = SUCCESS.toString();
    			}
    			else{
    				this.addError(response.getErrorMessage());
    				retVal['status']  = FAILURE.toString();
    			}
    
    		} catch (e) {
    			this.addError(e.toString());
    			retVal['status'] = FAILURE.toString();
    		}
    
    		ms.log("Connector Connector testConnection " + retVal['status'] );
    		if (retVal['status'] === FAILURE.toString())
    			retVal['error_message'] = errorMessage;
    		return retVal;
    	},
    
    	execute: function() {
    
    		var retVal = {};
    		retVal['status'] = SUCCESS.toString();
    
    		return retVal;
    	},
    
    	updateSource : function() {
    
    		ms.log("Bi-directional: Updating the source");
    		var jsonStr = this.probe.getAdditionalParameter("alerts"); //get all the alerts data from the Update Queue table
    		ms.log("JSON: " + jsonStr);
    		jsonStr = jsonStr + '';
    		var objJSON = JSON.parse(jsonStr);
    		var command = '';
    		var argument = '';
    		var jsonRes = '';
    		var url = this.probe.getAdditionalParameter("url");
    		var username =  this.probe.getParameter("username");
    		var password =  this.probe.getParameter("password");
    		var host =  this.probe.getParameter("host");
    		var result = false;
    		var retVal = {};
    
    		retVal = {};
    
    		if (objJSON == null){
    			this.addError("Received json is empty");
    			retVal['status']  = "" + FAILURE.toString();
    			retVal['error_message'] = errorMessage;
    			return retVal;
    		}
    		
    		if (url == undefined || url == null || url == '') {
    			this.addError("URL parameter is empty");
    			retVal['status']  = "" + FAILURE.toString();
    			retVal['error_message'] = errorMessage;
    			return retVal;
    		}
    
    		var alertsToSend = [];
    		var alertId = 0;
    		for (var i = 0; i < objJSON.length; ++i) {
    			var alert = objJSON[i];
    			for (var j = 0; j <  alert.value.length; ++j) {
    				if (alert.value[j].fieldName === 'incident' || alert.value[j].fieldName === 'remote_task_id'){
    					command = 'ticket_id';
    					argument = alert.value[j].newValue;
    				}
    				if (alert.value[j].fieldName === 'state' && (alert.value[j].oldValue === 'Open' || alert.value[j].oldValue === 'Reopen') && alert.value[j].newValue === 'Closed'){
    					command = 'close';
    				}
    				if (alert.value[j].fieldName === 'state' && alert.value[j].oldValue === 'Closed' && (alert.value[j].newValue === 'Open' || alert.value[j].newValue === 'Reopen')){
    					command = 'open';
    				}
    				if (command != ''){
    					this.probe.setParameter("action_performed", "true");
    
    					var alertToSend = {};
    					alertToSend.id = alert.key;
    					alertToSend.command = command;
    					alertToSend.ticket_id = argument;
    					
    					alertsToSend[alertId] = alertToSend;
    
    					command = '';
    					argument = '';
    					jsonRes = JSON.stringify(alertsToSend);
    					ms.log("jsonRes: " + jsonRes);
    					result = this.sendAlert(url, username, password, jsonRes);
    					if (result == false){
    						retVal['status']  = "" + FAILURE.toString();
    						retVal['error_message'] = errorMessage;
    						return retVal;	
    					}
    					alertsToSend = [];
    					alertId = 0;
    
    				}
    			}
    		}
    		retVal['status']  = "" + SUCCESS.toString();
    		return retVal;
    	},
    
    
    	sendAlert : function(url, user, pw, body) {
    		try {
    			var PostMethod = Packages.org.apache.commons.httpclient.methods.PostMethod;  
    			var GlideHTTPCient = Packages.com.glide.communications.HTTPClient;  
    			var httpClient = new GlideHTTPCient();  
    
    			var postMethod = new PostMethod(url); // put your endpoint URL here  
    			postMethod.addRequestHeader('X-Auth-Token', '...'); // add request headers, can use user and pw parameters for authentication  
    			postMethod.setRequestBody(body);
    
    			var httpStatus = httpClient.executeMethod(postMethod);  
    			var response = postMethod.getResponseBodyAsString();  
    			getMethod.releaseConnection();  
    
    			if(response.haveError()) {
    				this.addError("ERROR: " + response.getErrorMessage() + "  " + response.getBody());
    				return false;
    			}
    			
    			return true;
    			
    		} catch(err) {
    			this.addError("Error on sendAlert function. Failed to send data to the source. Error: " + err.message);
    			return false;
    		}
    	},
    
    	addError : function(message){
    		if (errorMessage === "")
    			errorMessage = message;
    		else
    			errorMessage += "\n" + message;
    		ms.log(message);
    	},
    	
    type: "ConnectorJS"
    });

    Troubleshooting

    If manual changes from alerts do not update the external source monitor, perform these checks:

    • Check to see if the bi-directional status on the connector is in error.
    • Check if changes are written to the queue (em_connector_update_queue) and check for their status.
    • Check if changes are being processed on the queue:
      • Yes: Check the MID log for errors.
      • No: Check the ECC queue for processing issues.

Example

Assume that a custom bi-directional connector must be created. The connector must receive event information from an OMi device. When a manual update is made to an alert, the connector must forward the changes back to the OMI external device. Required:
  • Write the MID Server custom bi-directional connector script include to enable the exchange of values to-and-from the OMi device external event source and the ServiceNow instance.
    • In the connector JavaScript, specify the information required for the updateSource function. This function receives the manual changes from alerts and sends them to the external source, according to the source instance. Use this updateSource function to handle and parse all the alert fields that should be updated in the external source.
    • After adding the update source method, update the test Connection method to test the bi-directional API as well.
  • Modify an existing connector definition, or create a new connector definition, to which the bi-directional connector script is associated. Thereafter, a custom connector instance is created that uses this connector definition.

In this step, create the custom bi-directional connector definition.

  1. Navigate to Event Management > Event Connectors (Pull) > Connector Definitions and click New.
  2. Fill in the fields as appropriate, including selecting the Bi-directional option.

    When the connector instance is configured as bi-directional, each manual update of an alert from this source instance is logged in the Update Queue (em_connector_update_queue) table.

  3. In the Alert field identifier field, specify the alert field that, if changed manually, causes the external monitoring system to be updated.

    The Update queue business rule that runs on the Alert table identifies each manual update of the alert and updates the connector queue with these changes. To determine if an update to the alert was caused manually or automatically from an event, the Last Update Time By Event field is examined. If this field has not changed, the business rule accepts the alert update as a manual update.

  4. Right-click the form header and select Save.
  5. In the Script type field, select JavaScript.
  6. In the JavaScript to run field, select the custom bi-directional connector script include.
  7. Click Update.

In this step, create the custom bi-directional connector instance and associate the new custom connector definition with it.

  1. Navigate to Event Management > Event Connectors (Pull) > Connector Instances and click New.
  2. Fill in the fields as appropriate. In the Connector definition field, select the custom connector definition that you created in the preceding procedure.
  3. Select the Bi-directional option
  4. Right-click the form header and select Save.
  5. Click Test Connector. If a failure result is returned, follow the instructions that are issued by the error to correct the problem and then run another test.
  6. When Test Connector returns a successful result, click the Active option
  7. Click Update.

    Every 30 seconds the Event Management - Queue connector processor job runs and processes all pending alerts in the Update Queue. These updates are sent to the MID Server using the ConnectorUtil script include.

    The Event Management - Queue connector processor schedule job dequeues alert changes and sends them to the MID Server. By default, this dequeue process is performed in batches of 1,000 alerts. You can configure this batch size using the evt_mgmt.max_update_source_records property.