如果未安装包,如何使Ansible执行shell脚本

如果未安装包,如何使Ansible执行shell脚本,ansible,Ansible,如果没有安装(rpm)包,如何使Ansible执行shell脚本?是否有可能利用yum模块?我认为在这种情况下,yum模块不会有帮助。它目前有3种状态:缺席、当前和最新。由于听起来您不想实际安装或删除软件包(至少在这一点上),因此您需要通过两个手动步骤来完成此操作。第一个任务将检查包是否存在,然后第二个任务将根据第一个命令的输出调用一个命令 如果使用“rpm-q”检查包是否存在,那么对于存在的包,输出将如下所示: # rpm -q httpd httpd-2.2.15-15.el6.centos

如果没有安装(rpm)包,如何使Ansible执行shell脚本?是否有可能利用yum模块?

我认为在这种情况下,yum模块不会有帮助。它目前有3种状态:缺席、当前和最新。由于听起来您不想实际安装或删除软件包(至少在这一点上),因此您需要通过两个手动步骤来完成此操作。第一个任务将检查包是否存在,然后第二个任务将根据第一个命令的输出调用一个命令

如果使用“rpm-q”检查包是否存在,那么对于存在的包,输出将如下所示:

# rpm -q httpd
httpd-2.2.15-15.el6.centos.1.x86_64
如果包不存在,则如下所示:

# rpm -q httpdfoo
package httpdfoo is not installed
因此,您的ansible任务将如下所示:

- name: Check if foo.rpm is installed
  command: rpm -q foo.rpm
  register: rpm_check

- name: Execute script if foo.rpm is not installed
  command: somescript
  when: rpm_check.stdout.find('is not installed') != -1
如果包存在,rpm命令也将以0退出,如果找不到包,rpm命令将以1退出,因此另一种可能性是使用:

when: rpm_check.rc == 1

基于上面的Bruce p答案,我们为apt/deb文件提供了一种类似的方法

- name: Check if foo is installed
  command: dpkg-query -l foo
  register: deb_check

- name: Execute script if foo is not installed
  command: somescript
  when: deb_check.stdout.find('no packages found') != -1
与此相关

将所有内容放在一起,完成Debian(Ubuntu)的playbook,该playbook仅在软件包已安装时更新:

---
- name: Update package only if already installed (Debian)
  hosts: all
  sudo: yes
  tasks:
    - name: Check if Package is installed
      shell: dpkg-query -W -f='${Status}' {{ package }} | grep 'install ok installed'
      register: is_installed
      failed_when: no
      changed_when: no

    - name: Update Package only if installed
      apt:
        name: {{ package }}
        state: latest
        update_cache: yes
      when: is_installed.rc == 0

遗憾的是,Ansible仍然没有内置支持进行简单的软件包更新,请参见示例:

您不应该使用
dpkg-l软件包,因为它不知道您的软件包是否已被删除或仍在安装。
相反,最好使用
dpkg-s包

要检查软件包是否已安装:
-
shell:dpkg-s软件包| grep“安装正常已安装”

或者,如果您不介意包裹处于搁置状态或其他状态:
-
shell:dpkg-s包| grep“已安装”

安装时返回0,否则返回1


(使用shell非常重要,因为我们使用的是管道
|

如果包可以通过系统包管理器(yum、apt等)本身安装,则可以使用ansible的check mode标志注册安装状态,而无需实际安装包

- name: check if package is installed
  package:
    name: mypackage
    state: present
  check_mode: true
  register: mypackage_check

- name: run script if package installed
  shell: myscript.sh
  when: not mypackage_check.changed 

我发现使用shell或命令模块不是“ansiblic”

我更喜欢使用yum模块和filter来检查包是否已经安装。例如,httpd包:

    - yum:
        list: httpd
      register: apache_service

    - assert:
        that:
          - "'installed' in apache_service|json_query('results[*].yumstate')"
      msg: 'httpd is not installed'

由于Ansible 2.5,您可以使用以下模块:


注意:您需要在目标系统上安装apt/rpm的python绑定,例如Debian的
python apt

该命令的问题是,如果
rpm-q
以0退出(未找到包),playbook将失败。为防止出现这种情况,请将:
ignore\u errors:True
附加到任务中,以便在后续任务中使用输出来安装rpm。此外,当:no
时,您可能需要添加
changed\u,以强制
命令
模块不要说某些内容已更改。此外,为了避免在找不到包时出现失败消息,您可以将
failed\u设置为:rpm\u check.rc>1
。当:rpm\u check.rc=1
时,它不是
failed\u吗。我没有看到大于1的数字。对于
ignore\u错误:yes
它仍然算作一个错误,因此
failed\u when:no
似乎是一个更好的选择。我需要添加
failed\u when:False
我想指出,从Ansible 2.1开始,apt模块有一个名为
only\u upgrade
的选项,这正是为此目的而设计的。文档中描述了这个开关:“只有在已经安装了软件包的情况下才安装/升级软件包”。@Erathiel我认为这个剧本解决的问题是,如果找到给定的软件包,就运行“特定”任务。因此,不一定是安装丢失的软件包,它可能是其他东西。
only\u upgrade
选项用于确保安装或更新软件包,就像
state
@Erathiel一样,OP需要进行if/then测试。他/她没有声明他们想实际安装任何东西。干杯。如果您希望它是幂等的,那么在:False时添加
changed\u。例如,使用
shell:dpkg--status{{package}}| grep'install ok installed'
比使用
命令:dpkg query-l{package}
更健壮。通过使用
package
模块而不是特定的
yum
one,这将使它成为最好的解决方案,因为它将在不止RHEL或Debian系列的Linux发行版上工作。做得好!这对我不起作用。如果未安装软件包,则会显示Ansible错误。我不得不在“检查软件包是否安装”部分添加“忽略错误:是”。什么版本?从RPM文件安装时,2.3.2.0会出错。它在2.4.0.0中得到了修复。当软件包未安装时,任务
检查软件包是否已安装
报告故障,事实上,当它成功运行并注册了变量
mypackage\u check
时,我不得不将其更改为
shell:dpkg-s package | grep-c“install ok installed”
在Debian上,grep没有返回0或1。使用
-c
选项,它返回找到的行数。
- name: Gather package facts
  package_facts:
    manager: auto

- name: Debug if package is present
  debug:
    msg: 'yes, mypackage is present'
  when: '"mypackage" in ansible_facts.packages'

- name: Debug if package is absent
  debug:
    msg: 'no, mypackage is absent'
  when: '"mypackage" not in ansible_facts.packages'