Ansible剧本Shell输出

79

我想使用像 ps、dstat 等命令来快速监控一些主机,使用 ansible-playbook。 ansible 命令本身完美地实现了我想要的功能,例如我会使用:

ansible -m shell -a "ps -eo pcpu,user,args | sort -r -k1 | head -n5"

它可以很好地打印出每个主机的所有标准输出,如下所示:

localhost | success | rc=0 >>
0.0 root     /sbin/init
0.0 root     [kthreadd]
0.0 root     [ksoftirqd/0]
0.0 root     [migration/0]

otherhost | success | rc=0 >>
0.0 root     /sbin/init
0.0 root     [kthreadd]
0.0 root     [ksoftirqd/0]
0.0 root     [migration/0] 

但是这需要我为每个任务保留一堆shell脚本,这不完全符合'ansible'的要求,因此我将其放入一个playbook中:

---
-
  hosts: all
  gather_facts: no
  tasks:
    - shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5

并使用-vv运行它,但输出基本上显示字典内容,换行符未按原样打印,因此结果像这样难以阅读:

changed: [localhost] => {"changed": true, "cmd": "ps -eo pcpu,user,args | sort -r -k1 
head -n5 ", "delta": "0:00:00.015337", "end": "2013-12-13 10:57:25.680708", "rc": 0,
"start": "2013-12-13 10:57:25.665371", "stderr": "", "stdout": "47.3 xxx    Xvnc4 :24
-desktop xxx:24 (xxx) -auth /home/xxx/.Xauthority -geometry 1920x1200\n
.... 
我尝试添加了register: var以及一个“debug”任务,以显示{{ var.stdout }},但结果当然是相同的。 是否有一种通过playbook运行命令的stdout/stderr输出可以得到漂亮格式化的方法?我可以想到许多可能的方法(使用sed格式化输出?将输出重定向到主机上的文件,然后获取该文件并在屏幕上echo它?),但由于我对shell/ansible的知识有限,这需要花费我一天时间去尝试。

https://serverfault.com/questions/537060/how-to-see-stdout-of-ansible-commands - JonnyJD
9个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
122

debug模块需要更多的关注,但目前你所能做的最好的就是使用这个:

- hosts: all
  gather_facts: no
  tasks:
    - shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
      register: ps

    - debug: var=ps.stdout_lines

它会生成如下输出:

ok: [host1] => {
    "ps.stdout_lines": [
        "%CPU USER     COMMAND",
        " 1.0 root     /usr/bin/python",
        " 0.6 root     sshd: root@notty ",
        " 0.2 root     java",
        " 0.0 root     sort -r -k1"
    ]
}
ok: [host2] => {
    "ps.stdout_lines": [
        "%CPU USER     COMMAND",
        " 4.0 root     /usr/bin/python",
        " 0.6 root     sshd: root@notty ",
        " 0.1 root     java",
        " 0.0 root     sort -r -k1"
    ]
}

2
你是如何让它将结果漂亮地打印出来的?当我这样做时,输出都在一行上。 - Michael Bylstra
3
接受了!这基本上是geerlingguy的答案,但使用stdout_lines而不是stdout可以使输出具有合理的格式。 - stijn
2
有关register action的相关文档。 - Ehtesh Choudhury
3
有没有办法将标准输出和标准错误输出合并成一个流? - PythonNut
2
@PythonNut 是的,你可以直接使用:- debug: var="ps.stdout_lines + [ ps.stderr ]" - Strahinja Kustudic
显示剩余2条评论

18

这只是一个开端:

- hosts: all
  gather_facts: no
  tasks:
    - shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
      register: ps

    - local_action: command echo item
      with_items: ps.stdout_lines

注意:有关ps.stdout_lines的文档已在此处涵盖:(“注册变量”章节)


1
这是一个开始,但输出的行似乎完全是随机顺序? - stijn
Ansible会逐行返回stdout,没有任何排序(我假设它只是运行不同的任务并按接收到的顺序打印行)。为了将每个主机的行保持在一起,在结尾处放置类似于|tr“\n”“~”这样的内容,将所有内容放入一行中,并在接收端再次拆分。 - Alex Lehmann

14

扩展leucos在他的答案中所说的,你也可以使用Ansible的谦逊的debug模块打印信息:

- hosts: all
  gather_facts: no
  tasks:
    - shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
      register: ps

    # Print the shell task's stdout.
    - debug: msg={{ ps.stdout }}

    # Print all contents of the shell task's output.
    - debug: var=ps

1
第一个调试任务只是打印出 "<cpu usage>",而第二个任务则会输出 "Hello world!"。 - stijn
对我来说,第一个调试条目(它只打印标准输出的第一行)返回 "msg": "12.7",第二个调试条目则打印了整个标准输出。我在本地主机(127.0.0.1)上运行了playbook。 - geerlingguy
@stijn "Hello world!" 是 msg 的默认值。http://docs.ansible.com/ansible/debug_module.html - backslash112

4

ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook /tmp/foo.yml -vvv

运行以上命令后,具有标准输出的任务将显示在以下部分中:

STDOUT:

What ever was in STDOUT

4

我发现使用ansible-playbook中的minimal stdout_callback可以得到类似于使用ad-hoc ansible的输出。

在你的ansible.cfg文件中(注意我在OS X上,所以请根据你的安装修改callback_plugins路径)

stdout_callback     = minimal
callback_plugins    = /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ansible/plugins/callback

这样,像你的 ansible-playbook 任务就能够实现

---
-
  hosts: example
  gather_facts: no
  tasks:
    - shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
像临时命令一样,输出如下所示。
example | SUCCESS | rc=0 >>
%CPU USER     COMMAND
 0.2 root     sshd: root@pts/3
 0.1 root     /usr/sbin/CROND -n
 0.0 root     [xfs-reclaim/vda]
 0.0 root     [xfs_mru_cache]

我正在使用ansible-playbook 2.2.1.0版本。


2
如果您需要特定的退出状态,Ansible提供了一种通过回调插件实现的方法。 示例。如果您需要100%准确的退出状态,则这是一个非常好的选择。 如果不需要特定的退出状态,您也可以始终使用 Debug 模块,这是此类用途的标准解决方案。 祝贺!

2

对于我来说,唯一有效的方法是这个(由于register+with_items组合):

- name: "download and distribute certs"
  shell: "python3 /tmp/bla.py {{ item.name }}"
  register: python3
  with_items: "{{ my_list }}"

- debug: msg="{{ item.stdout_lines | join("\n") }}"
  with_items: "{{ python3['results'] }}"

1

我个人在playbook中使用了几个shell或命令调用,并将其输出收集到不同的变量中。最后,我汇总信息并一次性列出所有信息,如下所示:

- ansible.builtin.shell: "df -h"
  register: disk

- ansible.builtin.shell: "free -m"
  register: mem

.....

- name: Summarize
  local_action: ansible.builtin.debug var={{ item }}
  become: no
  with_items: 
    - disk.stdout_lines
    - mem.stdout_lines

如果你使用以下方式调用它:

ANSIBLE_STDOUT_CALLBACK=minimal ansible-playbook getServerInfo.yml 

它提供了一个漂亮、干净的输出


0

如果您想仅使用Ansible执行此操作,那么这可能并不相关。但是,对于我来说,在我的 .bash_profile 中拥有一个函数,然后运行 _check_machine host1 host2 要容易得多。

function _check_machine() {
    echo 'hostname,num_physical_procs,cores_per_procs,memory,Gen,RH Release,bios_hp_power_profile,bios_intel_qpi_link_power_management,bios_hp_power_regulator,bios_idle_power_state,bios_memory_speed,'
    hostlist=$1
    for h in `echo $hostlist | sed 's/ /\n/g'`;
    do
        echo $h | grep -qE '[a-zA-Z]'
        [ $? -ne 0 ] && h=plabb$h
        echo -n $h,
        ssh root@$h 'grep "^physical id" /proc/cpuinfo | sort -u | wc -l; grep "^cpu cores" /proc/cpuinfo |sort -u | awk "{print \$4}"; awk "{print \$2/1024/1024; exit 0}" /proc/meminfo; /usr/sbin/dmidecode | grep "Product Name"; cat /etc/redhat-release; /etc/facter/bios_facts.sh;' | sed 's/Red at Enterprise Linux Server release //g; s/.*=//g; s/\tProduct Name: ProLiant BL460c //g; s/-//g' | sed 's/Red Hat Enterprise Linux Server release //g; s/.*=//g; s/\tProduct Name: ProLiant BL460c //g; s/-//g' | tr "\n" ","
         echo ''
    done
}

例如

$ _machine_info '10 20 1036'
hostname,num_physical_procs,cores_per_procs,memory,Gen,RH Release,bios_hp_power_profile,bios_intel_qpi_link_power_management,bios_hp_power_regulator,bios_idle_power_state,bios_memory_speed,
plabb10,2,4,47.1629,G6,5.11 (Tikanga),Maximum_Performance,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
plabb20,2,4,47.1229,G6,6.6 (Santiago),Maximum_Performance,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
plabb1036,2,12,189.12,Gen8,6.6 (Santiago),Custom,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
$ 

毫无疑问,这个函数对你来说是不起作用的。你需要适当地更新它。


输出结果还不错,但 Ansible 的一个优点是我不必费心处理主机列表/SSH/for 循环等等。所以我不会为了一个函数而放弃这种便利 :P - stijn
你没有回答问题。"...使用ansible-playbook" - Jason S
1
+1 指出可能有更好/更容易的工具来完成工作。仅仅因为Ansible是最新最棒的工具,并不意味着我们需要用重武器去杀鸡。Ansible被用于IT任务,如配置管理、应用程序部署、内部服务编排和供应。提问者只是想通过ps输出监控他的系统。抱歉,但Ansible并不是魔法。你需要在某个地方建立清单。如果不是ssh,那么就是Ansible。最后,如果一个for循环都那么难,那...我猜还是用Ansible吧。 - Mike S
1
嗨@MikeS,当然可以,但是我认为Ansible是否是正确的工具,这是另一个问题,更直接的问题是如何格式化Ansible输出。他也可能正在使用Ansible做其他事情,因此开销是值得的。那是另一种讨论。 - Jason S
你说得对。我想我是在回应stijn的评论,他谈到了Ansible作为一个工具对前端循环的方便性。我看到很多人评论说Ansible很容易使用,然后我们有了这样的问题,出现了各种“...它对我没用...”之类的评论。只是为了合理地打印输出?唉,我认为Ansible在这个问题上已经超出了它的能力范围。但只有这一个问题;你说得对- 他确实问了关于Ansible的问题,我不应该评判他的需求。我也讨厌在StackOverflow上看到这种情况。 - Mike S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,