[PYTHON] View logs in an easy-to-understand manner with Ansible

It may already be in other configuration management tools, or it may actually be in Ansible, but I couldn't find it, so I wrote the code at the "I wish I had something like this" level, so I'll post it.

I wrote it in Python because I wanted to avoid putting in extra things as much as possible, but since I was a beginner in Python and did not study the program properly, I think that I can peck everywhere in the heavy box. Put the code at the very end.

I'm forgetful, so I often ask, "Did you apply the playbook to that host?" There is a setting in Ansible's conf to take a log, but I thought it would be difficult to keep track of the log because most of the messages that flow at runtime are logged as they are.

Anyway, I want to see a list of when and what task of what playbook has been executed for the host.

The result of the code written in is as follows (indentation is appropriate)

ansible.png

I'm sorry it's hard to see. I'm sorry it's appropriate. Anyway, I want to display information in a sloppy manner like this. If you already have this kind of mechanism, please tell me without looking beyond this point.

About scripts

  1. Make sure that you can log in ansible conf (enable log =. If you use the default /var/log/ansible.log, don't forget to set permissions)
  2. If you delete the log, you cannot track the past status, so do not delete the log (it is meaningless unless you log from the time of operation)
  3. However, the log grows because the log increases due to the analysis of the playbook when the script is executed (sorry).
  4. It is assumed that the playbook is properly placed in one directory with the name .yml.
  5. Host range specification (www [0:10] .hoge etc.) is not supported.
  6. I got the group name on the way, but I couldn't think of how to display it in the list, so I just got it.

Then it is the following code.

list.py


#-*- coding: utf-8 -*-

import commands

#Text color setting
GREEN = '\033[92m'
YELLOW = '\033[93m'
RED ='\033[91m'
ENDC = '\033[0m'

#Specify the location of the log file
log=open('/var/log/ansible.log','r')

#Specify the location of the hosts file
hosts=open('/etc/ansible/hosts', 'r')

#Specify the playbook directory
ymldir='/etc/ansible/'

#First parse hosts and make a list

hostline = hosts.readline()
groupnames = []
groupnames.append('default')
hostnames = []
hostname = []

while hostline:
	if hostline.startswith("#") or hostline.startswith("\n"):
		pass
	elif hostline.startswith("["):
		groupnames.append(hostline.rstrip(']\n').lstrip('['))
		hostnames.append(hostname)
		hostname = []
	else:
		hostname.append(hostline.rstrip('\n'))
	hostline = hosts.readline()
else:
	hostnames.append(hostname)

#Make a list so far. groupname[default, webserver...] hostnames[ [default host, default host2] , [webserver..]]Stored in.

#Then check the playbook and make a list of the corresponding hosts and tasks to perform.
#Stores playbook filenames

playbooks=commands.getoutput('/bin/ls '+ymldir+' | grep .yml').split('\n')
playbookhosts=[]
playbookhost=[]
tasks=[]
task=[]

for i in playbooks:
	result = commands.getoutput('/usr/bin/ansible-playbook '+ymldir+i+' --list-hosts --list-tasks').split('\n')
	hostcount = 0
	taskcount = 0
	taskmode = 0
	for j in result:
		if "host count=" in j:
			hostcount = j[(j.rfind("=") + 1):]
			hostcount = int(hostcount)
		elif hostcount > 0:
			playbookhost.append(j.strip())
			hostcount -= 1
		if hostcount==0 and "play #" in j:
			taskmode = 1
		elif taskmode==1 and len(j.strip()) > 0:
			task.append(j.strip())
			
	playbookhosts.append(playbookhost)
	playbookhost=[]
	tasks.append(task)
	task=[]	

#Make a list so far. playbooks[playbook1.yml, playbook2.yml...] playbookhosts[ [playbook1 host 1,playbook2 host 2], [playbook3...]]]The same applies to tasks stored in

#I have all the necessary information (because the execution result and date and time on the log side are the rest), so I will tabulate it.
#A table for all tasks in the host playbook task.

disptable=[]
rows=[]

j = 0
for i in playbookhosts:
	hcount=len(playbookhosts[playbookhosts.index(i)]) 
	#Repeat for the number of hosts
	while hcount > 0:
		hcount -= 1
		tcount=len(tasks[j])
		#Repeat for the number of tasks
		while tcount > 0:
			tcount -= 1
			rows.append(playbookhosts[j][hcount])
			rows.append(playbooks[j])
			rows.append(tasks[j][tcount])
			disptable.append(rows)
			rows=[]
	j += 1

#Log analysis from here

line = log.readline()

while line:
	#Looking from the top, when ansible that is not a check is executed
	if "ansible-playbook" in line and ymldir in line and "--check" not in line and "--list-" not in line:
		#Maybe store the playbook running
		cbook = line[line.index(ymldir)+len(ymldir):line.index(".yml")+4]
	try:
		if cbook and "TASK" in line:
			#Store task
			ctask = line[line.index("TASK: [")+len("TASK :["):line.index("]")]
	except NameError:
		pass
	try:
		if cbook and ctask:
			if " changed:" in line:
				#retrieve host
				chost = line[line.index("[")+len("["):line.index("]")]
				#Distpable with matching host and task[[]]I want to add to. Overwrite if anything is recorded
				for i in disptable:
					if chost in i and cbook in i and ctask in i:
						try:
							if disptable[disptable.index(i)][3]:
								disptable[disptable.index(i)][3] = YELLOW + "changed" + ENDC
								disptable[disptable.index(i)][4] = line[:line.index(",")]
						except IndexError:
								disptable[disptable.index(i)].append(YELLOW + "changed" + ENDC)
								disptable[disptable.index(i)].append(line[:line.index(",")])
			elif " ok:" in line:
				#retrieve host
				chost = line[line.index("[")+len("["):line.index("]")]
				#disptable with matching host and task[[]]I want to add to. However, if changed is recorded, it will not be executed (because I want to know the change date and time)
				for i in disptable:
					if chost in i and cbook in i and ctask in i:
						try:
							if disptable[disptable.index(i)][3] != "changed":
								disptable[disptable.index(i)][3] = GREEN + "ok" + ENDC
								disptable[disptable.index(i)][4] = line[:line.index(",")]
						except IndexError:
								disptable[disptable.index(i)].append(GREEN + "ok" + ENDC)
								disptable[disptable.index(i)].append(line[:line.index(",")])
			elif " failed:" in line:
				#retrieve host
				chost = line[line.index("[")+len("["):line.index("]")]
				#Distpable with matching host and task[[]]I want to add to. Overwrite if anything is recorded
				for i in disptable:
					if chost in i and cbook in i and ctask in i:
						try:
							if disptable[disptable.index(i)][3]:
								disptable[disptable.index(i)][3] = RED + "failed" + ENDC
								disptable[disptable.index(i)][4] = line[:line.index(",")]
						except IndexError:
								disptable[disptable.index(i)].append(RED + "failed" + ENDC)
								disptable[disptable.index(i)].append(line[:line.index(",")])
	except NameError:
		pass
	line = log.readline()

#Display part

print "HOST\t\t\tPLAYBOOK\t\tTASK\t\tRESULT\t\tDATE"

disptable.sort()

j = 0;
prvhost=""
prvyml=""
for i in disptable:
	nowhost = disptable[j][0]
	nowyml = disptable[j][1]
	if nowhost==prvhost:
		nowhost="\t\t"
		if nowyml==prvyml:
			nowyml="\t\t"
	try:
		print nowhost + '\t\t' +  nowyml + '\t\t' + disptable[j][2] + '\t\t' + disptable[j][3] + '\t\t' + disptable[j][4]
	except IndexError:
		print nowhost + '\t\t' +  nowyml + '\t\t' + disptable[j][2] + '\t\t' + "no data" + '\t\t' + ""

	prvhost = disptable[j][0]
	prvyml = disptable[j][1]
	j += 1

Please let me know if there is a better way (I think there is definitely).

Recommended Posts

View logs in an easy-to-understand manner with Ansible
[Machine learning] Let's summarize random forest in an easy-to-understand manner
Put postfix 2.11 in source with ansible
Check if the configuration file is read in an easy-to-understand manner
I will explain how to use Pandas in an easy-to-understand manner.
[Python] I tried to summarize the set type (set) in an easy-to-understand manner.
Comparing the basic grammar of Python and Go in an easy-to-understand manner
I tried to summarize Cpaw Level 3 Write Up in an easy-to-understand manner
I tried to explain how to get the article content with MediaWiki API in an easy-to-understand manner with examples (Python 3)
Introduction to Deep Learning (1) --Chainer is explained in an easy-to-understand manner for beginners-
Create an image with characters in python (Japanese)
Send an email with Excel attached in Python
Since I touched Tensorflow for 2 months, I explained the convolutional neural network in an easy-to-understand manner with 95.04% of "handwritten hiragana" identification.
Stop an instance with a specific tag in Boto3
[For beginners] I want to explain the number of learning times in an easy-to-understand manner.
[Deep Learning from scratch] I tried to explain the gradient confirmation in an easy-to-understand manner.