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:
- Updating incidents, problems, and change requests
- Updating the ServiceNow configuration management database (CMDB)
- 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:
servicenow.itsm.incident
for managing incident ticketsservicenow.itsm.problem
for interacting with problemsservicenow.itsm.change_request
for handling changesservicenow.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.
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:
- lookup the change request by its number
- mark the change request as being worked on
- retrieve the affected configuration item from the change request
- perform requested operations on said configuration item, and finally
- 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.