[Ansible小贴士] 支撑nyanshible的技术 [cowsay/回调插件]
在与Ansible社区的人交谈时,我不经意地使用了词语“にゃんしぶる”,这导致了可能会生成一些在Ansible执行时出现猫咪的模块的讨论,所以我暂时试着在消息输出中实现“にゃんしぶる”,看看是否可行。

环境 –
[zaki@manager nyan]$ ansible --version
ansible 2.8.5
config file = /home/zaki/work/ansible/nyan/ansible.cfg
configured module search path = [u'/home/zaki/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Aug 7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
[zaki@manager nyan]$
[zaki@manager nyan]$ cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[zaki@manager nyan]$
另外,本文内容包括了cowsay的使用方法和修改方式,以及Ansible回调插件的简单构建方法。
我想试试,不要解释。
详细的内容稍后提到,只需要将以下脚本复制粘贴到/usr/local/bin/cowsay。(该脚本将根据参数对ASCII艺术进行整理并打印出来)
#!/usr/bin/perl
my $border = "-" x ((length $ARGV[-1]) + 2);
print <<"__EOL__";
$border
< $ARGV[-1] >
$border
\\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
__EOL__
给 /usr/local/bin/cowsay 增加执行权限 chmod 755 ,然后执行 Ansible 即可。
如果想要恢复原状,只需删除/usr/local/bin/cowsay即可。
牛说:“にゃんしぶる”
如果在Ansible执行时系统上安装了cowsay命令,则具备使用此命令输出任务名称的功能。
这部分是调用Ansible来使用cowsay的部分。
准备好自己的 cowsay 并进行尝试
在执行Ansible时,检查是否安装了cowsay是根据以下列表中是否存在执行文件来判断的。
b_COW_PATHS = (
b"/usr/bin/cowsay",
b"/usr/games/cowsay",
b"/usr/local/bin/cowsay", # BSD path for cowsay
b"/opt/local/bin/cowsay", # MacPorts path for cowsay
)
如果你在这些路径中放置了可执行的cowsay脚本,那就没问题了。换句话说,只有当执行Ansible时,路径(如~/local/bin/cowsay)中有cowsay存在,才会有反应。
所以,即使没有通过yum等安装cowsay,只要自行准备/usr/local/bin/cowsay,就可以在Ansible中使用nyanshible。
(※不要忘记使用chmod 755给予执行权限)
实施案例
比如说Perl脚本
#!/usr/bin/perl
my $border = "-" x ((length $ARGV[-1]) + 2);
print <<"__EOL__";
$border
< $ARGV[-1] >
$border
\\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
__EOL__
如果已安装原始的cowsay,并且没有进行其他特殊配置,则在Ansible中使用cowsay -W 60 -f default “消息”的格式会执行cowsay。
def banner_cowsay(self, msg, color=None):
if u": [" in msg:
msg = msg.replace(u"[", u"")
if msg.endswith(u"]"):
msg = msg[:-1]
runcmd = [self.b_cowsay, b"-W", b"60"]
if self.noncow:
thecow = self.noncow
if thecow == 'random':
thecow = random.choice(list(self.cows_available))
runcmd.append(b'-f')
runcmd.append(to_bytes(thecow))
runcmd.append(to_bytes(msg))
cmd = subprocess.Popen(runcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = cmd.communicate()
self.display(u"%s\n" % to_text(out), color=color)
这个函数的
runcmd = [self.b_cowsay, b"-W", b"60"]
[...]
runcmd.append(b'-f')
runcmd.append(to_bytes(thecow))
這一部分的內容。
所以,如果你想要创建自己的cowsay,你可以根据这个调用规范,取出最后一个参数并输出,这样就可以执行nyanshible了。
(在Perl中,脚本的参数可以通过@ARGV数组接收,要引用数组的末尾,可以使用数组索引-1来取出)
执行示例 lì)
[zaki@manager nyan]$ ansible-playbook playbook.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note
that the implicit localhost does not match 'all'
------------------
< PLAY [localhost] >
------------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
------------------------
< TASK [Gathering Facts] >
------------------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
ok: [localhost]
-------------
< TASK [ping] >
-------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
ok: [localhost]
------------
< PLAY RECAP >
------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[zaki@manager nyan]$
在 cowsay 中添加自定义模板并显示 “喵”
可以通过安装cowsay包并准备cowsay的输出模板来实现nyan式的效果。cowsay默认显示信息为牛的ASCII艺术,但是有多个样本显示格式,并且可以通过选项来改变显示方式。
女性工程师通过cowsay来提升女性魅力 – Qiita
咕噜牛说的设置
[zaki@manager nyan]$ cowsay Ansible
_________
< Ansible >
---------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
可供选择的模板
[zaki@manager nyan]$ cowsay -l
Cow files in /usr/share/cowsay:
beavis.zen blowfish bong bud-frogs bunny cheese cower default dragon
dragon-and-cow elephant elephant-in-snake eyes flaming-sheep ghostbusters
head-in hellokitty kiss kitty koala kosh luke-koala mech-and-cow meow milk
moofasa moose mutilated ren satanic sheep skeleton small sodomized
stegosaurus stimpy supermilker surgery telebears three-eyes turkey turtle
tux udder vader vader-koala www
[zaki@manager nyan]$
我来试着选择Tux
[zaki@manager nyan]$ cowsay -f tux Ansible
_________
< Ansible >
---------
\
\
.--.
|o_o |
|:_/ |
// \ \
(| | )
/'\_ _/`\
\___)=(___/
[zaki@manager nyan]$
那么这个模板在哪里呢?如同列表中的第一行“/usr/share/cowsay中的Cow文件”,它位于/usr/share/cowsay目录下。
[zaki@manager nyan]$ ls -F /usr/share/cowsay/
DragonAndCow.pm default.cow luke-koala.cow stimpy.cow
Example.pm dragon-and-cow.cow mech-and-cow.cow supermilker.cow
Frogs.pm dragon.cow meow.cow surgery.cow
MechAndCow.pm elephant-in-snake.cow milk.cow telebears.cow
Stegosaurus.pm elephant.cow moofasa.cow three-eyes.cow
TextBalloon.pm eyes.cow moose.cow turkey.cow
TuxStab.pm flaming-sheep.cow mutilated.cow turtle.cow
beavis.zen.cow ghostbusters.cow ren.cow tux.cow
blowfish.cow head-in.cow satanic.cow udder.cow
bong.cow hellokitty.cow sheep.cow vader-koala.cow
bud-frogs.cow kiss.cow skeleton.cow vader.cow
bunny.cow kitty.cow small.cow www.cow
cheese.cow koala.cow sodomized.cow
cower.cow kosh.cow stegosaurus.cow
这是一个Perl脚本,将AA设置为$the_cow变量的输出内容。
##
## TuX
## (c) pborys@p-soft.silesia.linux.org.pl
##
$the_cow = <<EOC;
$thoughts
$thoughts
.--.
|o_o |
|:_/ |
// \\ \\
(| | )
/'\\_ _/`\\
\\___)=(___/
EOC
[zaki@manager nyan]$
那你明白了吗?
##
## A cow wadvertising the World Wide Web, from lim@csua.berkeley.edu
##
$the_cow = <<EOC;
\\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
EOC
順便提一下,如果包含日语(多字节字符),使用UTF-8会出现乱码的情况,所以保存为UTF-16 LE格式。
[zaki@manager ~]$ cowsay -l
Cow files in /usr/share/cowsay:
beavis.zen blowfish bong bud-frogs bunny cat cheese cower default dragon
dragon-and-cow elephant elephant-in-snake eyes flaming-sheep ghostbusters
head-in hellokitty kiss kitty koala kosh luke-koala mech-and-cow meow milk
moofasa moose mutilated ren satanic sheep skeleton small sodomized
stegosaurus stimpy supermilker surgery telebears three-eyes turkey turtle
tux udder vader vader-koala www
只需要一个选择:↑添加了cat。
选择cat并执行。
[zaki@manager ~]$ cowsay -f cat Ansible
_________
< Ansible >
---------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
[zaki@manager ~]$
如果因为宗教原因等无法在/usr/share/cowsay作为文件的安装位置,那么可以将文件存储在/usr/local/share/cowsay/cat.cow,并在运行时通过环境变量COWPATH指定使用。(详细信息请参考man或cowsay的源代码)
[zaki@manager ~]$ COWPATH=/usr/local/share/cowsay cowsay -l
Cow files in /usr/local/share/cowsay:
cat
[zaki@manager ~]$ COWPATH=/usr/local/share/cowsay cowsay -f cat aaa
_____
< aaa >
-----
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
[zaki@manager ~]$
多种路径设置
[zaki@manager ~]$ COWPATH=/usr/local/share/cowsay:/usr/share/cowsay cowsay -l
Cow files in /usr/local/share/cowsay:
cat
Cow files in /usr/share/cowsay:
beavis.zen blowfish bong bud-frogs bunny cheese cower default dragon
dragon-and-cow elephant elephant-in-snake eyes flaming-sheep ghostbusters
head-in hellokitty kiss kitty koala kosh luke-koala mech-and-cow meow milk
moofasa moose mutilated ren satanic sheep skeleton small sodomized
stegosaurus stimpy supermilker surgery telebears three-eyes turkey turtle
tux udder vader vader-koala www
[zaki@manager ~]$
Ansible配置
由于已经准备好使用自定义模板在cowsay中输出消息,所以要进行从Ansible中选择指定模板的设置。
不过,只需在ansible.cfg文件中进行描述即可。
(如果自定义模板不在默认的/usr/local/share/cowsay等位置,需要添加COWPATH=/usr/local/share/cowsay)
答案: ANSIBLE_COW_SELECTION 的选择
[defaults]
cow_selection = cat
顺便说一下,如果在这里写下像tux这样的,通过cowsay -l命令显示的列表项目,则Ansible的输出将根据该内容进行。另外,如果选择random,则每次输出都会从可用模板中随机选择一个。
执行例子
[zaki@manager nyan]$ ansible-playbook playbook.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note
that the implicit localhost does not match 'all'
__________________
< PLAY [localhost] >
------------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
________________________
< TASK [Gathering Facts] >
------------------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
ok: [localhost]
_____________
< TASK [ping] >
-------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
ok: [localhost]
____________
< PLAY RECAP >
------------
\ ∧_∧
.ミ,,・_・ミ
ヾ(,_uuノ
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[zaki@manager nyan]$
禁用cowsay
[defaults]
nocows = True
或者可以使用yum erase cowsay来删除它。
回调插件用于猫咪模拟。
使用cowsay到目前为止,只是输出了play名和task名,所以无法像正常时一样可爱的猫咪,错误时毛发竖起的猫咪之类的事情。
如果要处理这个区域,可以使用回调插件(平时可以用”默认的错误不好看呀,哦对了,使用yaml的stdout_callback会变得好看”这种东西)来实现。
我將自己創建一個用於「Nyanshiburu的callback plugin」的插件,但只需要基於「預設的callback plugin,當未進行任何設定時使用」來進行開發,如果只是修改顯示的程度,則可以輕鬆地通過複製粘貼完成。
使用Ansible的回调插件来表达突然死亡(echo-sd) – Qiita
回调插件与Ansible本身一样,都是使用Python编写的。对于在CentOS7上通过epel安装的ansible 2.8版本,插件的源代码位于/usr/lib/python2.7/site-packages/ansible/plugins/callback/*.py目录下。
制作一个“にゃんしぶる”回调插件。
首先,在playbook所在的目录中创建一个callback_plugins子目录,并将default.py复制到该目录下并重命名为nyansible.py。
[zaki@manager nyan]$ mkdir callback_plugins/
[zaki@manager nyan]$ cp /usr/lib/python2.7/site-packages/ansible/plugins/callba
ck/default.py callback_plugins/nyansible.py
[zaki@manager nyan]$ ll callback_plugins/
合計 20
-rw-r--r--. 1 zaki zaki 17488 11月 4 12:36 nyansible.py
[zaki@manager nyan]$
以默认设置为基础的最简单的复制粘贴代码
只要更改默认回调插件的显示部分消息,就可以了。
不过,直接写入日语(多字节码)会导致乱码,所以需要进行相应的处理。
中文版暂不提供日语支持。
ERROR! Unexpected Exception, this is probably a bug: Non-ASCII character '\xce' in file /home/zaki/work/ansible/nyan/callback_plugins/nyansible.py on line 89, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details (nyansible.py, line 89)
如果要在脚本中使用日语,需要在脚本的第一行(通常,对于普通的Python脚本,shebang(#!/usr/bin/env python3之类的指令)在第一行,如果有的话就在第二行)中指定编码。
如果使用UTF-8编码的话,
# -*- coding: utf-8 -*-
写。
[WARNING]: Failure using method (v2_runner_on_ok) in callback plugin
(<ansible.plugins.callback.nyansible.CallbackModule object at 0x7fda2cacc410>):
'ascii' codec can't decode byte 0xe0 in position 0: ordinal not in range(128)
另外,在使用日语时,需要添加表示Unicode编码的u” … “的描述。(添加u前缀以显示ok和changed的消息输出)
self._display.display("fatal: [%s]: FAILED! => %s" ...
在中文中,可以将其翻译为“用于”。
self._display.display(u"エラー: [%s]: FAILED! => %s" ...
写成中文。
修改点示例
[zaki@manager nyan]$ diff -u /usr/lib/python2.7/site-packages/ansible/plugins/c
allback/default.py callback_plugins/nyansible.py
--- /usr/lib/python2.7/site-packages/ansible/plugins/callback/default.py 2019-09-13 06:12:55.000000000 +0900
+++ callback_plugins/nyansible.py 2019-11-04 12:59:50.520091324 +0900
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
# (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@@ -48,7 +49,7 @@
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'stdout'
- CALLBACK_NAME = 'default'
+ CALLBACK_NAME = 'nyansible'
def __init__(self):
@@ -86,11 +87,11 @@
else:
if delegated_vars:
- self._display.display("fatal: [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'],
+ self._display.display(u"Σ(;Φ ω Φ): [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'],
self._dump_results(result._result)),
color=C.COLOR_ERROR, stderr=self.display_failed_stderr)
else:
- self._display.display("fatal: [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)),
+ self._display.display(u"Σ(;Φ ω Φ): [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)),
color=C.COLOR_ERROR, stderr=self.display_failed_stderr)
if ignore_errors:
@@ -107,9 +108,9 @@
self._print_task_banner(result._task)
if delegated_vars:
- msg = "changed: [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
+ msg = u"ฅ/ᐠ。ᆽ。ᐟ \: [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
else:
- msg = "changed: [%s]" % result._host.get_name()
+ msg = u"ฅ/ᐠ。ᆽ。ᐟ \: [%s]" % result._host.get_name()
color = C.COLOR_CHANGED
else:
if not self.display_ok_hosts:
@@ -119,9 +120,9 @@
self._print_task_banner(result._task)
if delegated_vars:
- msg = "ok: [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
+ msg = u"ฅ(^・ω・^ฅ): [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
else:
- msg = "ok: [%s]" % result._host.get_name()
+ msg = u"ฅ(^・ω・^ฅ): [%s]" % result._host.get_name()
color = C.COLOR_OK
self._handle_warnings(result._result)
[zaki@manager nyan]$
运行示例
---
- hosts: localhost
tasks:
- ping:
- shell: date
- yum:
name: ruby
[zaki@manager nyan]$ ansible-playbook playbook.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note
that the implicit localhost does not match 'all'
PLAY [localhost] ***************************************************************
TASK [Gathering Facts] *********************************************************
ฅ(^・ω・^ฅ): [localhost]
TASK [ping] ********************************************************************
ฅ(^・ω・^ฅ): [localhost]
TASK [shell] *******************************************************************
ฅ/ᐠ。ᆽ。ᐟ \: [localhost]
TASK [yum] *********************************************************************
Σ(;Φ ω Φ): [localhost]: FAILED! => {"changed": false, "changes": {"installed": ["ruby"]}, "msg": "You need to be root to perform this command.\n", "rc": 1, "results": ["Loaded plugins: fastestmirror\n"]}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[zaki@manager nyan]$
继承了易于查看错误的YAML插件的”Nyan”框架
不使用默认插件,而是基于一个能将错误消息以yaml格式输出的yaml插件进行构建。
yaml插件的源代码位于/usr/lib/python2.7/site-packages/ansible/plugins/callback/yaml.py。然而,即使查看该源代码,也无法找到输出”ok”、”changed”和”fatal”的代码。
那么它是如何实现的呢?Ansible的回调插件需要创建一个CallbackModule类,而yaml插件是基于默认插件进行继承开发的。
也就是说,基本处理都直接使用了默认插件的处理方式,只是输出处理部分使用了yaml.dump()函数进行实现。
if abridged_result:
dumped += '\n'
dumped += to_text(yaml.dump(abridged_result, allow_unicode=True, width=1000, Dumper=AnsibleDumper, default_flow_style=False))
所以,我们可以通过继承YAML插件并重写输出”ok/changed/fatal”等内容的方法来实现。
创建一个继承yaml插件类的CallbackModule类,用于nyanshible。
首先创建一个只继承了yaml插件而没有实现任何自定义处理的类。就像这样。
我取名叫nyaml。
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
callback: nyaml
type: stdout
short_description: nyaml-ized Ansible screen output
'''
from ansible.plugins.callback.yaml import CallbackModule as CallbackModule_yaml
class CallbackModule(CallbackModule_yaml):
"""
nyansible and nyaml /ᐠ。ꞈ。ᐟ\
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'stdout'
CALLBACK_NAME = 'yaml'
在这个时候,如果在ansible.cfg中写入stdout_callback = nyaml(与普通的yaml插件一样),它就会工作。
实现消息输出处理
从默认插件的源代码中借用消息输出处理函数。
目标函数包括v2_runner_on_ok()和v2_runner_on_failed()等。
首先复制并尝试运行这些函数。
然后,会输出一些警告信息,提示缺少一些定义。
TASK [Gathering Facts] ********************************************************* [WARNING]: Failure using method (v2_runner_on_ok) in callback plugin
(<ansible.plugins.callback.nyaml.CallbackModule object at 0x7fc66f796c50>):
global name 'TaskInclude' is not defined
TASK [ping] ********************************************************************
TASK [shell] *******************************************************************
TASK [yum] ********************************************************************* [WARNING]: Failure using method (v2_runner_on_failed) in callback plugin
(<ansible.plugins.callback.nyaml.CallbackModule object at 0x7fc66f796c50>):
global name 'C' is not defined
据称,任务中没有包括Include和C。
因此,我們從默認插件的代碼中再次借用這個功能(基本上是這個操作的循環)。
所以,整個代碼的結構大致如此。
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = '''
callback: nyaml
type: stdout
short_description: nyaml-ized Ansible screen output
'''
from ansible.plugins.callback.yaml import CallbackModule as CallbackModule_yaml
from ansible import constants as C
from ansible.playbook.task_include import TaskInclude
from ansible.utils.color import colorize, hostcolor
class CallbackModule(CallbackModule_yaml):
"""
nyansible and nyaml /ᐠ。ꞈ。ᐟ\
"""
CALLBACK_VERSION = 2.0
CALLBACK_TYPE = 'stdout'
CALLBACK_NAME = 'yaml'
def v2_runner_on_failed(self, result, ignore_errors=False):
delegated_vars = result._result.get('_ansible_delegated_vars', None)
self._clean_results(result._result, result._task.action)
if self._last_task_banner != result._task._uuid:
self._print_task_banner(result._task)
self._handle_exception(result._result, use_stderr=self.display_failed_stderr)
self._handle_warnings(result._result)
if result._task.loop and 'results' in result._result:
self._process_items(result)
else:
if delegated_vars:
self._display.display(u"Σ(;Φ ω Φ): [%s -> %s]: FAILED! => %s" % (result._host.get_name(), delegated_vars['ansible_host'],
self._dump_results(result._result)),
color=C.COLOR_ERROR, stderr=self.display_failed_stderr)
else:
self._display.display(u"Σ(;Φ ω Φ): [%s]: FAILED! => %s" % (result._host.get_name(), self._dump_results(result._result)),
color=C.COLOR_ERROR, stderr=self.display_failed_stderr)
if ignore_errors:
self._display.display("...ignoring", color=C.COLOR_SKIP)
def v2_runner_on_ok(self, result):
delegated_vars = result._result.get('_ansible_delegated_vars', None)
if isinstance(result._task, TaskInclude):
return
elif result._result.get('changed', False):
if self._last_task_banner != result._task._uuid:
self._print_task_banner(result._task)
if delegated_vars:
msg = u"ฅ/ᐠ。ᆽ。ᐟ\: [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
else:
msg = u"ฅ/ᐠ。ᆽ。ᐟ\: [%s]" % result._host.get_name()
color = C.COLOR_CHANGED
else:
if not self.display_ok_hosts:
return
if self._last_task_banner != result._task._uuid:
self._print_task_banner(result._task)
if delegated_vars:
msg = u"ฅ(^・ω・^ฅ): [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host'])
else:
msg = u"ฅ(^・ω・^ฅ): [%s]" % result._host.get_name()
color = C.COLOR_OK
self._handle_warnings(result._result)
if result._task.loop and 'results' in result._result:
self._process_items(result)
else:
self._clean_results(result._result, result._task.action)
if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result:
msg += " => %s" % (self._dump_results(result._result),)
self._display.display(msg, color=color)
用nyaml插件制作猫舌
使用这个nyaml插件来执行ansible-playbook。
[zaki@manager nyan]$ ansible-playbook playbook.yml
[WARNING]: provided hosts list is empty, only localhost is available. Note
that the implicit localhost does not match 'all'
PLAY [localhost] ***************************************************************
TASK [Gathering Facts] *********************************************************
ฅ(^・ω・^ฅ): [localhost]
TASK [ping] ********************************************************************
ฅ(^・ω・^ฅ): [localhost]
TASK [shell] *******************************************************************
ฅ/ᐠ。ᆽ。ᐟ\: [localhost]
TASK [yum] *********************************************************************
Σ(;Φ ω Φ): [localhost]: FAILED! => changed=false
changes:
installed:
- ruby
msg: |-
You need to be root to perform this command.
rc: 1
results:
- |-
Loaded plugins: fastestmirror
PLAY RECAP *********************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
[zaki@manager nyan]$
资料参考
-
- ねこのAA
猫 | ねこ – 可愛い顔文字 | 顔文字まとめサイト
2chのかわいいAA/顔文字まとめ: 10/10更新 猫
顺便提一句,筆者從我的圖標你也可以看出來,我喜歡兔子?。