forked from mikeder/shinken-ticketer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ticketer.py
177 lines (164 loc) · 4.92 KB
/
ticketer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python
# ticketer.py
# Shinken command script for generating ServiceNow Incidents via the REST API
import datetime
import getopt
import json
import sqlite3
import sys
import os
import pprint
import requests
# Determine current working directory and set database path
cwd = os.path.dirname(os.path.realpath(__file__))
dbpath = cwd + '/data/incident.db'
# Read credentials for accessing ServiceNow REST API
with open('credentials.json') as data_file:
sn_access = json.load(data_file)
data_file.close()
def main(argv):
# Initialize/Preallocate list to hold alarm details
alarm = ['type','host','addr','srvc','output','state']
try:
opts, args = getopt.getopt(argv,"h", ["help", "type=", "host=", "addr=",
"srvc=", "output=", "state=", "initdb"])
except getopt.GetoptError as err:
print(err)
usage()
sys.exit(2)
# If no options are given, print usage
if not opts:
usage()
# Handle all the options and arguments passed in
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt == '--type':
alarm[0] = arg
elif opt == '--host':
alarm[1] = arg
elif opt == '--addr':
alarm[2] = arg
elif opt == '--srvc':
alarm[3] = arg
elif opt == '--output':
alarm[4] = arg
elif opt == '--state':
alarm[5] = arg
elif opt == '--initdb':
initdb()
# Generate new ticket if this is a new alarm
if alarm[0] == 'PROBLEM':
createInc(alarm)
# Resolve existing ticket if the alarm has recovered
elif alarm[0] == 'RECOVERY':
resolveInc(alarm)
# Print usage, even though this is called by a daemon?
def usage():
print("Usage: ticketer.py --type --host --addr --srvc --output --state")
print("--type $NOTIFICATIONTYPE$")
print("--host $HOSTNAME$")
print("--addr $HOSTADDRESS$")
print("--srvc $SERVICEDESC$")
print("--output $SERVICEOUTPUT$")
print("--state $SERVICESTATE$")
# Setup sqlite database
def initdb():
sql = '''
CREATE TABLE IF NOT EXISTS
incident(id INTEGER PRIMARY KEY,
date DATETIME,
sysid TEXT,
host TEXT,
srvc TEXT)'''
db = sqlite3.connect(dbpath)
cursor = db.cursor()
cursor.execute(sql)
db.commit()
db.close()
print("Database successfully created.")
# Add new incident record to database
def dbAdd(sysid,host,srvc):
date = datetime.datetime.now()
sql = '''
INSERT INTO incident(date, sysid, host, srvc)
VALUES(?,?,?,?)'''
values = [(date,sysid,host,srvc)]
db = sqlite3.connect(dbpath)
cursor = db.cursor()
cursor.executemany(sql,values)
db.commit()
db.close()
print('New record added to database.')
# Lookup an incident record in the database and pass ID to dbDel()
def dbLookup(host,srvc):
sql = '''
SELECT sysid FROM incident WHERE host = ? AND srvc = ?'''
db = sqlite3.connect(dbpath)
db.text_factory = str
cursor = db.cursor()
values = [(host,srvc)]
print(values)
cursor.execute(sql,(host,srvc))
sysid = cursor.fetchone()
db.close()
return sysid
# Delete resolved incident record from database
def dbDel(sysid):
sql = '''
DELETE FROM incident WHERE sysid = ?'''
db = sqlite3.connect(dbpath)
cursor = db.cursor()
try:
cursor.execute(sql,sysid)
db.commit()
db.close()
print("Record deleted")
except Exception as err:
print('\033[1;91mThere was an error while deleting the record\033[1;m')
print('\033[1;91m%s\033[1;m' % err)
pass
# Create new ticket in Service Now
def createInc(alarm):
print("Creating ticket...")
### Insert call to SN API here and grab sysid from response body
url = sn_access["api"] + 'now/table/incident'
user = sn_access["user"]
password = sn_access["pass"]
alarmType = alarm[0]
host = alarm[1]
addr = alarm[2]
srvc = alarm[3]
output = alarm[4]
state = alarm[5]
headers = {"Accept":"application/json","Content-Type":"application/json"}
payload = {}
payload["short_description"] = "%s %s is %s" % (host,srvc,state)
payload["state"] = "1"
payload["incident_state"] = "1"
payload["contact_type"] = "alert"
payload["description"] = "Type: %s\nHost: %s\nService: %s\nOutput: %s" \
% (alarmType, host, srvc, output)
payload["comments"] = "AutoGenerated by Shinken"
r = requests.post(url, data=json.dumps(payload), headers=headers \
, auth=(user,password))
data = json.loads(r.content)
# Walks JSON response and grabs sys_id to insert into database
sysid = data["result"]["sys_id"]
number = data["result"]["number"]
print("Status Code: %d" % r.status_code)
print("Incident Num: %s" % number)
dbAdd(sysid,host,srvc)
# Resolve incident when alarm has cleared
def resolveInc(alarm):
host = alarm[1]
srvc = alarm[3]
sysid = dbLookup(host,srvc)
if not sysid:
print("No record found, nothing to resolve")
else:
print("Resolving ticket and removing entry for %s" % sysid)
dbDel(sysid)
if __name__ == "__main__":
main(sys.argv[1:])