Objective:
Ansible results By default is output to the CLI terminal and log inside, used to saltsatck the returners data callback, also very much like Ansible also have, at first did not know this function, oneself also simple to achieve such a function.
My implementation is to do some output logic inside the module. When using the Ansible Runner API, it is runner the code at the back and finally adds a section to the Redis output logic. The output of the data here is somewhat unique, but it can only be done in terms of modules and APIs. If it is using playbook words, according to my previous ideas, and then continue to change the source code ansbile. These two days to listen to Shen Zan said, Ansible has a callback_plugins function, can make some judgments about the state of execution, such as execution success, execution failure, asynchronous execution, asynchronous execution failure, playbook start, end, and so on.
I do not say complex, simply say an example, the implementation of the results, are pushed into the redis inside, can also be temporarily deposited into the SQLite database, but this section of the code I have to shield, interested friends to engage in. For the data inside the Redis can write a page display, specifically record the wrong problem, the success of pass away.
The code is as follows |
Copy Code |
#xiaorui. cc
Import OS Import time Import Sqlite3 Import Redis Import JSON
dbname = '/tmp/setup.db ' time_format= '%y-%m-%d%h:%m:%s '
Try con = sqlite3.connect (dbname) cur = con.cursor () Except Pass
def log (host, data):
# if Type (data) = = Dict: # invocation = Data.pop (' invocation ', None) # if Invocation.get (' module_name ', None)!= ' Setup ': # return # # facts = data.get (' ansible_facts ', None) # # now = Time.strftime (Time_format, Time.localtime ()) # # try: # ' Host ' is a unique index # Cur.execute ("REPLACE into Inventory" (now, host, Arch, Dist, distvers, Sys,kernel) VALUES (?,?,?,?,?,?,?); ", # ( # Now, # facts.get (' Ansible_hostname ', None), # facts.get (' ansible_architecture ', None), # facts.get (' ansible_distribution ', None), # facts.get (' ansible_distribution_version ', None), # facts.get (' Ansible_system ', None), # facts.get (' Ansible_kernel ', None) # )) # Con.commit () # except: # Pass # Class Callbackmodule (object): def RUNNER_ON_OK (self, Host, res): R = Redis. Redis (host= ' 127.0.0.1 ', port=6379, db=0) R.set (Host,str (res))
f = open ('/tmp/11 ', ' a ') F.write (str (host)) F.write (str (RES)) F.close () Log (host, res) def runner_on_failed (self, host, res, ignore_errors=false): f = open ('/tmp/11 ', ' a ') F.write (' Nbadn ') F.close () Log (host, res) |
You can still receive all of the facts data.
Although I use the above example Redis,sqlite database, in fact, I personally recommend the use of MongoDB such a document database. Because Ansible main runner function, give callbacks pass a variable called res, he is a Dict object, if put to Redis hash,sqlite of various fields, enough to annoy you, if direct MONGO, it is simple, Direct Insert! Oh, my.
Here in show a mail callbacks code, scene is, very time-consuming task, when the execution completed, see the results? But you can also continue to look at the terminal, since we talked about Callbacks_plugins, you can push the results into your mailbox, of course, only to send you wrong, there are problems. The following callback code needs to be replaced with its own mailbox, password, SMTP server.
The code is as follows |
Copy Code |
#xiaorui. cc
Import Smtplib
def Mail (subject= ' ansible error mail ', sender= ' <root> ', to= ' root ', Cc=none, Bcc=none, Body=none): If not body: BODY = Subject
SMTP = Smtplib. SMTP (' localhost ')
Content = ' from:%sn '% sender Content = ' to:%sn '% to If cc: Content + = ' cc:%SN '% cc Content + = ' Subject:%snn '% Subject Content + + Body
addresses = To.split (', ') If cc: Addresses + = Cc.split (', ') If Bcc: Addresses + = Bcc.split (', ')
For address in addresses: Smtp.sendmail (sender, address, content)
Smtp.quit ()
Class Callbackmodule (object):
""" This is ansible callback plugin mails errors to interested parties. """ def runner_on_failed (self, host, res, ignore_errors=false): If ignore_errors: Return Sender = ' "Ansible:%s" <root> '% host Subject = ' Failed:% (module_name) s% (Module_args) s '% res[' invocation '] BODY = ' The following task failed for host ' + Host + ': nn% (module_name) s% (Module_args) snn '% res[' invocation '] If ' stdout ' in Res.keys () and res[' stdout ']: Subject = res[' stdout '].strip (' RN '). Split (' n ') [-1] Body + = ' with the following output in standard Output:nn ' + res[' stdout '] + ' nn ' If ' stderr ' in Res.keys () and res[' stderr ']: Subject = res[' stderr '].strip (' RN '). Split (' n ') [-1] Body + = ' with the following output in standard Error:nn ' + res[' stderr '] + ' nn ' If ' msg ' in Res.keys () and res[' msg ']: Subject = res[' msg '].strip (' RN '). Split (' n ') [0] Body + = ' with the following Message:nn ' + res[' msg '] + ' nn ' Body + + ' A complete dump of the ' error:nn ' + str (RES) Mail (Sender=sender, Subject=subject, Body=body)
def runner_on_unreachable (self, Host, res): Sender = ' "Ansible:%s" <root> '% host If Isinstance (res, basestring): Subject = ' unreachable:%s '% Res.strip (' RN '). Split (' n ') [-1] BODY = ' A error occured for host ' + Host + ' with the following Message:nn ' + res Else Subject = ' unreachable:%s '% res[' msg '].strip (' RN '). Split (' n ') [0] BODY = ' A error occured for host ' + Host + ' with the following Message:nn ' + res[' msg '] + ' nna complete dump of the Error:nn ' + str (RES) Mail (Sender=sender, Subject=subject, Body=body)
def runner_on_async_failed (self, host, res, Jid): Sender = ' "Ansible:%s" <root> '% host If Isinstance (res, basestring): Subject = ' Async failure:%s '% Res.strip (' RN '). Split (' n ') [-1] BODY = ' A error occured for host ' + Host + ' with the following Message:nn ' + res Else Subject = ' Async failure:%s '% res[' msg '].strip (' RN '). Split (' n ') [0] BODY = ' A error occured for host ' + Host + ' with the following Message:nn ' + res[' msg '] + ' nna complete dump of the Error:nn ' + str (RES) Mail (Sender=sender, Subject=subject, Body=body) |
What if you don't want to send an email and don't want to get into the database? That's a little low-end. Write directly to the file.
The official gave an example, everybody follow the template to write on the line.
The code is as follows |
Copy Code |
Import OS Import time Import JSON
time_format= "%b%d%Y%h:%m:%s" msg_format= "% (now) s-% (category) s-% (data) SNN"
If not os.path.exists ("/var/log/ansible/hosts"): Os.makedirs ("/var/log/ansible/hosts")
def log (host, category, data): If type (data) = = Dict: If ' verbose_override ' in data: # Avoid logging extraneous data from facts data = ' omitted ' Else data = Data.copy () invocation = Data.pop (' invocation ', None) data = json.dumps (data) If invocation is not None: data = Json.dumps (invocation) + "=>%s"% data
Path = Os.path.join ("/var/log/ansible/hosts", host) now = Time.strftime (Time_format, Time.localtime ()) FD = open (path, "a") Fd.write (msg_format% dict (Now=now, Category=category, Data=data)) Fd.close ()
Class Callbackmodule (object): """ Logs playbook results, per host, in/var/log/ansible/hosts """
def on_any (self, *args, **kwargs): Pass
def runner_on_failed (self, host, res, ignore_errors=false): Log (host, ' FAILED ', res)
def RUNNER_ON_OK (self, Host, res): Log (host, ' OK ', res)
def runner_on_skipped (self, Host, Item=none): Log (host, ' skipped ', ' ... ')
def runner_on_unreachable (self, Host, res): Log (host, ' unreachable ', res)
def runner_on_no_hosts (self): Pass
def runner_on_async_poll (self, host, res, Jid, clock): Pass
def RUNNER_ON_ASYNC_OK (self, host, res, Jid): Pass
def runner_on_async_failed (self, host, res, Jid): Log (host, ' async_failed ', res)
def playbook_on_start (self): Pass
def playbook_on_notify (self, host, handler): Pass
def playbook_on_no_hosts_matched (self): Pass
def playbook_on_no_hosts_remaining (self): Pass
def playbook_on_task_start (self, Name, is_conditional): Pass
def playbook_on_vars_prompt (self, varname, private=true, Prompt=none, Encrypt=none, Confirm=false, Salt_size=none, Salt=none, Default=none): Pass
def playbook_on_setup (self): Pass
def playbook_on_import_for_host (self, Host, imported_file): Log (host, ' imported ', imported_file)
def playbook_on_not_import_for_host (self, Host, missing_file): Log (host, ' notimported ', missing_file)
def playbook_on_play_start (self, name): Pass
def playbook_on_stats (self, stats): Pass |
You can also do what you want to do with the webhooks hook way.
The various states of callbacks are still many, and the words of each function are well understood.
Like what:
On_any has him everywhere! Any state he had triggered.
runner_on_failed failure
RUNNER_ON_OK success
Runner_on_unreachable network can not reach
Runner_on_no_hosts No hosts
Asynchronous execution of Runner_on_async_poll tasks
When Playbook_on_start playbook executes,
Wait a minute.... Try it yourself!
The code is as follows |
Copy Code |
Class Callbackmodule (object):
def on_any (self, *args, **kwargs): Pass
def runner_on_failed (self, host, res, ignore_errors=false): Log (host, ' FAILED ', res)
def RUNNER_ON_OK (self, Host, res): Log (host, ' OK ', res)
def runner_on_skipped (self, Host, Item=none): Log (host, ' skipped ', ' ... ')
def runner_on_unreachable (self, Host, res): Log (host, ' unreachable ', res)
def runner_on_no_hosts (self): Pass
def runner_on_async_poll (self, host, res, Jid, clock): Pass
def RUNNER_ON_ASYNC_OK (self, host, res, Jid): Pass
def runner_on_async_failed (self, host, res, Jid): Log (host, ' async_failed ', res)
def playbook_on_start (self): Pass
def playbook_on_notify (self, host, handler): Pass
def playbook_on_no_hosts_matched (self): Pass
def playbook_on_no_hosts_remaining (self): Pass
def playbook_on_task_start (self, Name, is_conditional): Pass
def playbook_on_vars_prompt (self, varname, private=true, Prompt=none, Encrypt=none, Confirm=false, Salt_size=none, Salt=none, Default=none): Pass
def playbook_on_setup (self): Pass
def playbook_on_import_for_host (self, Host, imported_file): Log (host, ' imported ', imported_file)
def playbook_on_not_import_for_host (self, Host, missing_file): Log (host, ' notimported ', missing_file)
def playbook_on_play_start (self, name): Pass
def playbook_on_stats (self, stats): Pass |
We can simply look at the ansible callbacks source code.
Two classes are provided, one for supply ansible-playbook and one for supply ansible, the CLI. Depending on the situation, call a different function, first will hit the terminal, log logs, and finally the custom callbacks Plug-ins.