How to make Ansible execute a shell script if a package is not installed

后端 未结 7 1054
执念已碎
执念已碎 2021-01-30 01:48

How can I make Ansible execute a shell script if a (rpm) package is not installed? Is it somehow possible to leverage the yum module?

相关标签:
7条回答
  • 2021-01-30 01:56

    I don't think the yum module would help in this case. It currently has 3 states: absent, present, and latest. Since it sounds like you don't want to actually install or remove the package (at least at this point) then you would need to do this in two manual steps. The first task would check to see if the package exists, then the second task would invoke a command based on the output of the first command.

    If you use "rpm -q" to check if a package exists then the output would look like this for a package that exists:

    # rpm -q httpd
    httpd-2.2.15-15.el6.centos.1.x86_64
    

    and like this if the package doesn't exist:

    # rpm -q httpdfoo
    package httpdfoo is not installed
    

    So your ansible tasks would look something like this:

    - 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
    

    The rpm command will also exit with a 0 if the package exists, or a 1 if the package isn't found, so another possibility is to use:

    when: rpm_check.rc == 1
    
    0 讨论(0)
  • 2021-01-30 01:58

    I find using shell or command module is not "ansiblic".

    I prefer to use yum module and json_query filter to check if a package is already installed. E.g. httpd package :

        - yum:
            list: httpd
          register: apache_service
    
        - assert:
            that:
              - "'installed' in apache_service|json_query('results[*].yumstate')"
          msg: 'httpd is not installed'
    
    0 讨论(0)
  • 2021-01-30 02:08

    Related to this.

    Putting everything together, complete playbook for Debian (Ubuntu) which Updates package only if it's already installed:

    ---
    - 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
    

    Sadly Ansible still hasn't built-in support for making simple package updating, see ex: https://github.com/ansible/ansible/issues/10856

    0 讨论(0)
  • 2021-01-30 02:09

    Based on the Bruce P answer above, a similar approach for apt/deb files is

    - 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
    
    0 讨论(0)
  • 2021-01-30 02:12

    Since Ansible 2.5, you can use the package_facts module:

    - 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'
    

    Note: you need the python bindings for apt/rpm installed on the target, e.g. python-apt for Debian.

    0 讨论(0)
  • 2021-01-30 02:14

    You shouldn't be using dpkg -l package because it has no idea if your package has been removed or is still installed.
    Instead it's probably better to use dpkg -s package.

    To check if the package is installed :
    - shell: dpkg -s package | grep 'install ok installed'
    or if you don't mind the package on hold or other states :
    - shell: dpkg -s package | grep 'installed'
    This return 0 when installed and 1 if not.

    (It's important to use the shell as we are using a pipe |)

    0 讨论(0)
提交回复
热议问题