Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b7e738c
Add files to gitignore used for development
MRichards99 Apr 23, 2018
2432065
Add basic structure to readme
MRichards99 Apr 23, 2018
0d87a52
Add more files to gitignore
MRichards99 Apr 24, 2018
d43ff7b
Add section 'Using Script'
MRichards99 Apr 26, 2018
c6f0982
Add AppendSpreadsheet.py
MRichards99 Apr 26, 2018
be5ab94
Cleanup existing code
MRichards99 Apr 26, 2018
906b472
Add functionality to put data into spreadsheet
MRichards99 Apr 26, 2018
2e8e34a
Remove Callouts.xls being opened
MRichards99 Apr 27, 2018
c4cbc07
Convert script to use openpyxl
MRichards99 Apr 27, 2018
73adc1f
Add .xlsx files to gitignore
MRichards99 Apr 27, 2018
34f2712
Merge branch 'master' into develop-script
MRichards99 Apr 27, 2018
bbfee53
Separate time and date ticket got created
MRichards99 Apr 27, 2018
3eb7aca
Change ticket ID to int and centre cell
MRichards99 Apr 27, 2018
8791dc2
Add hyperlinks to ticket IDs
MRichards99 Apr 30, 2018
b7e6fab
Merge cells and input meeting date
MRichards99 Apr 30, 2018
8f0b3b6
Add border creation to spreadsheet
MRichards99 Apr 30, 2018
619ac99
Cleanup border changes
MRichards99 Apr 30, 2018
51feba2
Update method of grabbing alarm name
MRichards99 May 8, 2018
6b505f6
Remove unneeded print statement
MRichards99 May 8, 2018
0a98ab1
Add service cell editing
MRichards99 May 8, 2018
d5a22fa
Align all cells on rows relevant to this week's callouts
MRichards99 May 8, 2018
1cfc2f2
Wrap text on cells
MRichards99 May 8, 2018
5039dd2
Add data about host
MRichards99 May 8, 2018
7722f35
Add functionality to add data dependent on working hours
MRichards99 May 8, 2018
8e807de
General code cleanup
MRichards99 May 8, 2018
43a27fd
Add error handling
MRichards99 May 8, 2018
a37ee45
Add error handling for missing Results.tsv
MRichards99 May 8, 2018
a6cfaa1
Add to README
MRichards99 May 8, 2018
610673d
Merge branch 'master' into develop-script
MRichards99 May 8, 2018
3a7bfce
Change method of grabbing alarm
MRichards99 May 14, 2018
80cbd3b
Clean README
MRichards99 May 14, 2018
ff4e0c7
Merge branch 'master' into develop-script
MRichards99 May 14, 2018
78a6b63
Remove unneeded print statement
MRichards99 May 21, 2018
80745cc
Update AppendSpreadsheet.py
BenCEdwards Oct 8, 2018
0cf4e71
Update README.md
BenCEdwards Oct 8, 2018
7299985
Added 'fts' to services
BenCEdwards Oct 15, 2018
9720ab7
Update AppendSpreadsheet.py
BenCEdwards Mar 29, 2019
bc8bd01
Update README.md
BenCEdwards Mar 29, 2019
74de33a
Future Proofing
JHaydock-Pro Apr 1, 2019
2e37c62
Corrected Text alignment
JHaydock-Pro Apr 2, 2019
eb589de
Updated expected datetime format
JHaydock-Pro Jun 10, 2019
9a5c06a
Simplfied Spreadsheet
JHaydock-Pro Jun 10, 2019
2e69e58
Shared RT search
JHaydock-Pro Jun 10, 2019
29abe74
Update README.md
JHaydock-Pro Jun 10, 2019
5c6b49b
Update README.md
JHaydock-Pro Jun 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,9 @@ ENV/

# mypy
.mypy_cache/
Results.tsv
Callouts.xls
OnCall Spreadsheet Notes.txt
*.xml
*.iml
*.xlsx
187 changes: 187 additions & 0 deletions AppendSpreadsheet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import csv, sys, time, os
from openpyxl import load_workbook
from openpyxl.styles import Alignment, Side, Border
from datetime import datetime

NEW_TICKETS_FILE_NAME = "Results.tsv"
SPREADSHEET_NAME = "Callouts.xlsx"
SHEET_NAME = "Callouts %s" % datetime.now().year

try:
with open(NEW_TICKETS_FILE_NAME) as tsv:
try:
wb = load_workbook(SPREADSHEET_NAME)
except FileNotFoundError:
print(SPREADSHEET_NAME, 'doesn\'t exist (weekly spreadsheet), please add this file to the directory '
'of this script')
print('Directory of script:', os.path.dirname(os.path.realpath(__file__)))
time.sleep(4)
sys.exit()

try:
currentSheet = wb[SHEET_NAME]
except KeyError:
print('Sheet named \'' + SHEET_NAME + '\' doesn\'t exist')
print('Either create a sheet with this name in', SPREADSHEET_NAME, 'or edit script code so it finds a sheet '
'that does exist')
time.sleep(4)
sys.exit()

# Find which row to start appending spreadsheet
alarmColumn = currentSheet['A']
print('Calculating where to append spreadsheet')

startAppending = False
i = 1 # Start at 1 as first result will always be 'column header'
while not startAppending:
if alarmColumn[i].value is None:
startAppending = True
startingRowNumber = i + 1
i += 1

print('Will append spreadsheet from row #' + str(startingRowNumber))

# Skips first row of TSV file due to column headers
iterResults = iter(csv.reader(tsv, dialect="excel-tab"))
next(iterResults)

# Extracting data from TSV file
i = 0
nagiosFiller = "Nagios issued"
hostFiller = "on_host_"
for row in iterResults:
hostStart = None
service = None
hostCheck = True
workingHours = False
ticketID = int(row[0])

ticketCreated = datetime.strptime(row[3], '%a %b %d %H:%M:%S %Y')
dateCreated = ticketCreated.strftime('%d/%m/%Y')
#Excel date time counts days and seconds since 1900-01-00 but mistakenly treats 1900 as a leap year
excelTicketCreated = ticketCreated - datetime(1899, 12, 30)
timeCreated = float(excelTicketCreated.seconds) / 86400

# Is callout in work hours (8:30-5:00 converted into percent of day)?
weekday = ticketCreated.isoweekday()
if (60*8+30)/(24*60) < timeCreated < 17/24 and weekday < 6:
workingHours = True

# Get Nagios alarm (or subject if not from Nagios)
alarm = row[1]
if nagiosFiller in alarm:
for k in range(len(nagiosFiller), len(alarm)):
if 'T' in alarm[k]:
alarm = alarm[k:]
break

# Service
if 'ceph' in alarm.lower():
service = 'CEPH'
elif 'lcgdb' in alarm.lower() or 'database' in alarm.lower():
service = 'DATABASE'
elif 'castor' in alarm.lower():
service = 'CASTOR'
elif 'arc-ce' in alarm.lower():
service = 'CE'
elif 'bdii' in alarm.lower():
service = 'BDII'
elif 'dss' in alarm.lower():
service = 'DISK Server'
elif 'fts' in alarm.lower():
service = 'FTS'
elif 'ipv6' in alarm.lower() or 'network' in alarm.lower():
service = 'NETWORK'
elif 'eql-varray' in alarm.lower():
service = 'Hypervisor'
elif 'condor' in alarm.lower():
service = 'BATCH'
elif 'argus' in alarm.lower():
service = 'Argus'

# Get hostname from Nagios alarm
if hostFiller in alarm:
j = len(alarm) - 1
while hostCheck:
if alarm[j] == '_':
hostStart = j
hostCheck = False
j -= 1
hostname = alarm[hostStart + 1:]

# Putting data into spreadsheet
currentRow = startingRowNumber + i
currentSheet.cell(row=currentRow, column=1, value=alarm)
if hostStart is not None:
currentSheet.cell(row=currentRow, column=2, value=hostname)
currentSheet.cell(row=currentRow, column=3, value=dateCreated)
currentSheet.cell(row=currentRow, column=4, value=timeCreated)
if service is not None:
currentSheet.cell(row=currentRow, column=6, value=service)
# RT query
currentSheet.cell(row=currentRow, column=5, value=ticketID)
currentSheet.cell(row=currentRow, column=5).hyperlink = 'https://helpdesk.gridpp.rl.ac.uk/Ticket/Display' \
'.html?id=' + str(ticketID)
if workingHours:
currentSheet.cell(row=currentRow, column=8, value='N/A')
currentSheet.cell(row=currentRow, column=10, value='Work hours')
i += 1

# Merge cells
currentDate = datetime.now().strftime('%d-%b')
currentSheet.cell(row=startingRowNumber, column=12, value=currentDate)
currentSheet.merge_cells(start_row=startingRowNumber, start_column=12, end_row=currentRow, end_column=12)

# Setting inner borders and cell alignment
rows = currentSheet.iter_rows(min_row=startingRowNumber, min_col=1, max_row=currentRow, max_col=17)
innerBorderStyle = Side(border_style='thin', color='FF000000')
innerBorderFormat = Border(left=innerBorderStyle, right=innerBorderStyle, top=innerBorderStyle,
bottom=innerBorderStyle)
for row in rows:
for cell in row:
if cell.column == 1 or cell.column == 11:
# These columns need to be horizontally left aligned (alarm and comment columns)
cell.alignment = Alignment(horizontal='left', vertical='center', wrap_text=True)
else:
cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
# print(cell.column)

cell.border = innerBorderFormat

# Setting outer border
# Code found at: https://stackoverflow.com/questions/34520764/apply-border-to-range-of-cells-using-openpyxl
# Written by Yaroslav Admin, edited by Adam Stewart
outerRows = currentSheet.iter_rows(min_row=startingRowNumber, min_col=1, max_row=currentRow, max_col=17)
outerBorderStyle = Side(border_style='medium', color='FF000000')
outerRows = list(outerRows)
max_y = len(outerRows) - 1
for pos_y, cells in enumerate(outerRows):
max_x = len(cells) - 1 # index of the last cell
for pos_x, cell in enumerate(cells):
border = Border(
left=cell.border.left,
right=cell.border.right,
top=cell.border.top,
bottom=cell.border.bottom)

# Checking if an edge cell
if pos_x == 0:
border.left = outerBorderStyle
if pos_x == max_x:
border.right = outerBorderStyle
if pos_y == 0:
border.top = outerBorderStyle
if pos_y == max_y:
border.bottom = outerBorderStyle

# Set new border only if it's one of the edge cells
if pos_x == 0 or pos_x == max_x or pos_y == 0 or pos_y == max_y:
cell.border = border

wb.save(SPREADSHEET_NAME)
print('Spreadsheet changes saved')
except FileNotFoundError:
print(NEW_TICKETS_FILE_NAME, '(this week\'s tickets) not found, please add to the same directory of the script')
print('Directory of script:', os.path.dirname(os.path.realpath(__file__)))
time.sleep(4)
sys.exit()
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,37 @@
# oncall
# Automating OnCall Spreadsheet
This is a Python script to aid filling in the OnCall spreadsheet. The spreadsheet is used during the 3pm meeting on a Monday to discuss callouts from the past week.
The script takes data from a TSV file downloaded from RT using a specific search (see 'Using Script') and appends it to the ongoing OnCall spreadsheet (found within Tier 1's section on the TWiki).

## Required Packages
Only openpyxl is needed for this script. The script was written using version 2.5.3 of this module.

## Using Script
There are a couple of steps to using this script as there will be some cleanup to do once the script has executed.

### Pre-Script Execution
1. Load the saved search `OnCall Spreadsheet` under `Tier1a-support's saved searches` or create a custom search with the following criteria:
- Queue is OnCall
- Status is new or open
- Subject not like 'NoCall'
- Subject not like 'Test_Nagios' (test tickets)
- Subject not like 'Downtime Expiry Report'
- Sort ID by ascending
- Set the first four display columns to the following order:
- id
- Subject
- Status
- Created

2. Download spreadsheet (.TSV file) from search results (press 'Spreadsheet' hyperlink towards top right of the page)
3. Put OnCall spreadsheet (found in TWiki within Tier 1 section) and TSV file in same folder as script and then run script

### Post-Script Execution
1. Format column D as Time
2. Fill in any blank cells the script didn't fill from the following columns:
- Host
- Service
- People involved
- Handled by
- Any helpful comments
3. Upload to TWiki
4. After the meeting, resolve all tickets from the OnCall queue search, except the ones where the situation is still ongoing