Automating ServiceNow with Red Hat Ansible Automation Platform

May 13, 2021 - Words by Tadej Borovšak

May 13, 2021
Words by Tadej Borovšak

This post was originally published on the Ansible blog.

IT service management (ITSM) is a collection of policies and processes for the management and support of IT services. The main focus of ITSM is increasing the value of the customers service chain. But without the proper automation support, providing IT services can quickly become a major time-sink.

This is where the Red Hat Ansible Automation Platform and the Red Hat Ansible Certified Content Collection for ServiceNow come into play. Ansible Automation (with some help from existing Ansible content) can automate just about any task, while the modules from this Certified Collection allow us to keep the ServiceNow information up to date.

This Collection was designed and developed by the XLAB Steampunk team in close collaboration with Red Hat Ansible, specifically keeping end-users in mind. ServiceNow modules have an intuitive user interface backed by a robust implementation, offering support for things Ansible users expect (e.g., check mode and change detection).

In this post, we will look at a few sample Ansible Playbooks that take care of essential tasks such as:

  1. Updating incidents, problems, and change requests
  2. Updating the ServiceNow configuration management database (CMDB)
  3. Using the CMDB as an inventory source

Installing the Certified Content Collection for ServiceNow

We can download the servicenow.itsm Collection from automation hub or Ansible Galaxy. Before we can access content in automation hub, we must first configure our credentials in the Ansible configuration file. For details, please refer to the “Hands On With Ansible Collections” blog post.

Once we have our credentials, we can install the ServiceNow Collection by running the following command:

$ ansible-galaxy collection install servicenow.itsm

If everything goes according to plan, we now have access to the following modules:

  1. servicenow.itsm.incident for managing incident tickets
  2. servicenow.itsm.problem for interacting with problems
  3. servicenow.itsm.change_request for handling changes
  4. servicenow.itsm.configuration_item for managing the CMDB

Each of the modules also has a counterpart that gives us read-only access to ServiceNow records.

The Certified Content Collection for ServiceNow also contains an inventory plugin called servicenow.itsm.now that allows us to use CMDB as an inventory source.

To verify nothing went awry, we can display the documentation for one of the modules by executing the following command:

$ ansible-doc servicenow.itsm.incident

If Ansible did not yell at us, we are all set.

Managing incidents, the Ansible way

Creating a new incident ticket using Ansible is reasonably straightforward, but before we can do that, we need to tell Ansible where our ServiceNow instance lives and what credentials to use. We will do that by setting three environment variables:

$ export SN_HOST='https://dev12345.service-now.com'
$ export SN_USERNAME='user'
$ export SN_PASSWORD='pass'

Now that we have our credentials ready, we can create a new incident. The minimal Ansible playbook would look something like this:

---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: Create new incident
      servicenow.itsm.incident:
        state: new
        short_description: Demo incident

Once the previous playbook finishes executing, we will find a new incident listed in ServiceNow.

ServiceNow incident ticket, created using Ansible

ServiceNow incident ticket, created using Ansible

We can update an existing incident by providing either a ticket number or system id of the incident record. Ansible will compare the current and the desired states of the incident and make necessary changes to get them in sync.

---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: Update incident
      servicenow.itsm.incident:
        number: INC0010022
        state: in_progress

If we run Ansible with the --diff switch, it will report what changes it implemented to the incident record:

TASK [Update incident with a problem information] *************************
--- before
+++ after
@@ -50,7 +50,7 @@
     "parent": "",
     "parent_incident": "",
     "priority": "5",
-    "state": "new",
+    "state": "in_progress",
     "reassignment_count": "0",
     "reopen_count": "0",
     "reopened_by": "",
@@ -71,10 +71,10 @@
     "sys_domain": "global",
     "sys_domain_path": "/",
     "sys_id": "2396e496074f2010d4a1fa9e7c1ed01c",
-    "sys_mod_count": "0",
+    "sys_mod_count": "1",
     "sys_tags": "",
     "sys_updated_by": "admin",

We can also delete an existing incident by setting the state parameter to absent.

---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: Delete incident
      servicenow.itsm.incident:
        number: INC0010022
        state: absent

We can interact with problems and change requests in the same manner. However, managing configuration items is a bit different, so lets focus on this area next.

Updating the CMDB

Because the ServiceNow CMDB has more than one configuration item type, we need to specify the sys_class_name parameter when adding new items. By default, the servicenow.itsm.configuration_item module will use the cmdb_ci system class name, but we can change it to any other cmdb_ci-derived class.

---
- name: Demonstrate CMDB management
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Simulate VM creation
      ansible.builtin.set_fact:
        instance:
          name: some-name
          id: vm1234567890
          public_ip_address: 1.2.3.4
 
    - name: Register the newly-created VM instance
      servicenow.itsm.configuration_item:
        name: "{{ instance.name }}"
        sys_class_name: cmdb_ci_vm_instance
        ip_address: "{{ instance.public_ip_address }}"
        other:
          vm_inst_id: "{{ instance.id }}"

We used the generic other parameter that can contain arbitrary key-value pairs in the last task. Because ServiceNow tables are extensible, all modules have this parameter. We can use the other parameter to set column values that modules do not expose as top-level parameters. All ServiceNow Ansible modules have this parameter.

When updating or deleting an existing item, we do not have to specify the system class name because the module will automatically retrieve the name from the current record. But, we do have to provide a sys_id parameter value.

---
- name: Demonstrate CMDB item update and deletion
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Update the VM state
      servicenow.itsm.configuration_item:
        sys_id: b0ccabf1c0a80009001f14fd151d8df0
        install_status: in_maintenance
 
    - name: Remove item from CMDB
      servicenow.itsm.configuration_item:
        sys_id: b0ccabf1c0a80009001f14fd151d8df0
        state: absent

Dynamic inventory

The CMDB can also serve as an inventory source. Because configuration items that represent servers and virtual machines (VMs) usually contain IP addresses, we can use them as an inventory source.

The minimal configuration for the inventory plugin looks like this:

---
plugin: servicenow.itsm.now

When used as an inventory source, the plugin will list all servers from the cmdb_ci_server table. We can automatically group and filter inventory hosts based on the conditions specified in the group_by configuration option:

---
plugin: servicenow.itsm.now
group_by:
  os:
    includes:
      - Linux Red Hat
      - Windows XP

In the previous example, Ansible created two groups: one for Windows XP and one for Linux computers. The inventory plugin performs as much filtering as possible on the backend, minimizing the amount of downloaded data.

We can also configure which column values the inventory plugin adds as host variables:

---
plugin: servicenow.itsm.now
 
columns:
  - name
  - classification
  - cpu_type
 
group_by:
  os:
    includes:
      - Linux Red Hat
      - Windows XP

To test our configuration, we can execute the following command:

$ ansible-inventory -i inventory.now.yaml --graph --vars

We assumed that we stored the inventory configuration in the inventory.now.yaml file. The output should look something like this:

@all:
 |--@Linux_Red_Hat:
 |  |--P1000019
 |  |  |--{ansible_host = my1.server.com}
 |  |  |--{classification = Production}
 |  |  |--{cpu_type = Intel}
 |  |  |--{name = SAP-SD-01}
 |--@Windows_XP:
 |  |--P1000020
 |  |  |--{ansible_host = my2.server.com}
 |  |  |--{classification = Production}
 |  |  |--{cpu_type = Intel}
 |  |  |--{name = SAP-SD-02}
 |--@ungrouped:

And now that we know how to use individual modules and the inventory plugin, it is time for the grand finale.

Automatic resolution of a standard change request

Standard change requests are pre-approved procedures with minimal risks, and these properties make them prime candidates for automation.

So without any further ado, here is the playbook that will:

  1. lookup the change request by its number
  2. mark the change request as being worked on
  3. retrieve the affected configuration item from the change request
  4. perform requested operations on said configuration item, and finally
  5. close the change request
---
- hosts: localhost
  gather_facts: false
  tasks:
    - name: Mark change request as in progress
      servicenow.itsm.change_request:
        number: "{{ change_number }}"
        state: implement
      register: change
 
    - name: Fetch configuration item we will update
      servicenow.itsm.configuration_item_info:
        sys_id: "{{ change.record.cmdb_ci }}"
      register: citem
 
    - name: Create an in-memory inventory with the item
      ansible.builtin.add_host:
        name: host_to_update
        ansible_host: "{{ citem.record.ip_address }}"
 
- hosts: host_to_update
  tasks:
    - name: Simulate some work
      ansible.builtin.debug:
        msg: Doing real work here
 
- hosts: localhost
  gather_facts: false
  tasks:
    - name: Mark change request as done
      servicenow.itsm.change_request:
        number: "{{ change_number }}"
        state: closed

Who could have thought that one can stuff this much awesomeness into a single playbook?

The future is automatic

And this brings us to the end of today’s post. We covered quite a lot yet still only managed to scratch the surface of what is possible. So head over to automation hub or Ansible Galaxy, download the ServiceNow ITSM Ansible Collection, and start exploring. You can see this new solution in action and learn how to take your service delivery efforts to next level by watching this demo.

If you need help with your ServiceNow process automation and integration with the Red Hat Ansible Automation Platform, reach out to our team at XLAB Steampunk who can help you get up and running in no time.


Social media

Keep up with what we do on our social media.