Using ansible to install previously downloaded patches.

Latest response

I've got some hosts that need to get a snapshot of available at the time that other systems are being updated.

It is considered critical that these systems get exactly what was available to them right then, and not anything that comes out in the interim days between downloading and installing those patches.

In the past I've solved this by doing a download only on the ones that have to wait, and then installing them from those local files later.

I'm working on using ansible to accomplish this.

My download only playbook looks like this, and works just fine.

---
 - hosts: inventory.names

   strategy: free
   become_user: root
   become: yes
   become_method: sudo


   tasks:
       #   - name: create a temp directory
   - file:
       path: /temp-dir/
       state: directory
       owner: me
       group: me
       mode: 0644

   - name: run yum update and download only
     yum:
       name: '*'
       state: latest
       download_dir: /temp-dir
       download_only: yes

So, again, this one works. I get that its not perfect, but it works. Later I hope to combine the playbook I use to update the others, with this one so that I can do it all from one script.

In any case, my question is this. How do I install those packages from a playbook, without knowing those package names?

I was trying this:

---
 - hosts: a.test.system

   strategy: free
   become_user: root
   become: yes
   become_method: sudo


   tasks:
   - name: run yum update from previously downloaded files.
     yum:
       name: "{{ item }}"
       state: present
       with_fileglob:
         - "{{/timp2/*.rpm}}"

This seems good according to yml syntax, but isnt working as expected.


playbooks]$ ansible-playbook -K yumupdatelocal.yml BECOME password: PLAY [test.system] ******************************************************************************************* TASK [Gathering Facts] ********************************************************************************************** ok: [test.system] TASK [run yum update from previously downloaded files.] ************************************************************* fatal: [test.system]: FAILED! => {"msg": "template error while templating string: unexpected '/'. String: {{/timp2/*.rpm}}"} PLAY RECAP ********************************************************************************************************** test.system : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

So, I could use help in two places.

1, what am I doing wrong in this playbook.

2, If there is a better way to do this, please enlighten me. I'd LOVE to be able to just use options with the yum module to make it install from local files, without already having a list, I just cant see how to do it.

Responses

I'm not very knowledgeable with ansible so I'm probably wrong, but does the fileglob need the {{'s?

I thought it'd work with just quotations around it like "/timp2/*.rpm"

Sadly I've tried the heck out of that. I Only have those because the syntax checker finally stopped complaining about it when I added them.

I'm hoping there is a simple way to achieve the overall goal I'm after.

I think it shall work like this:

   tasks:
   - name: run yum update from previously downloaded files.
     yum:
       name: "{{ item }}"
       state: present
     with_fileglob:
         - "/timp2/*.rpm"

Hi Gary,

I am not an Ansible guru, but why the change from state: latest in the top playbook

to state: present in the bottom playbook?

Regards,

Jan Gerrit Kootstra

Hi, as Jan noticed: state: latest will cause a package update. state: present only ensures a package is installed, but dos not care abbot the version except you specific a package version. But if you specify a file to install (what is the case here) the only allowed value is state: present I believe Gary just needs to remove 2 spaces before with_fileglob, since with_fileglob is not a property of yum.

Jan and Jonas, thank you for your input.

I did a little more research and determined that the with_fileglob is (apparently) only going to match against files on the ansible controller machine. So I guess I need to use the find module instead.

So far I'm not having a lot of luck there.

Here is my new playbook.

 ---
  - hosts: test.system
    gather_facts: no #because I'm running this thing way too often while testing to wait for gather_facts

    strategy: free
    become_user: root
    become: yes
    become_method: sudo


    tasks:
    - name: get a list of downloaded patch files.
      find:
        file_type: file
        paths: '/timp2/'
        patterns: '*.rpm'
      register: find_results

    - name: print find_results
      #debug: var=item
      debug: var=item.path
      with_items: '{{find_results.files}}'
      #with_items: '{{find_results}}'

    - name: install those patches
      yum:
        name: '{{find_results}}'
        state: present
     #with_items: '{{find_results.files}}'
     #with_items: item.path

stuff commented out is just things I tried that didnt work.

ONE of the outputs of that debug statement. The others being the same except being other files.

ok: [test.system] => (item={u'rusr': True, u'uid': 0, u'rgrp': True, u'xoth': False, u'islnk': False, u'woth': False, u'nlink': 1, u'issock': False, u'mtime': 1559836357.0, u'gr_name': u'root', u'path': u'/timp2/microcode_ctl-1.17-33.13.el6_10.x86_64.rpm', u'xusr': False, u'atime': 1560778040.3630188, u'inode': 278049, u'isgid': False, u'size': 3101056, u'isdir': False, u'ctime': 1560369030.3201864, u'isblk': False, u'wgrp': False, u'xgrp': False, u'isuid': False, u'dev': 64768, u'roth': True, u'isreg': True, u'isfifo': False, u'mode': u'0644', u'pw_name': u'root', u'gid': 0, u'ischr': False, u'wusr': True}) => {
    "ansible_loop_var": "item",
    "item": {
        "atime": 1560778040.3630188,
        "ctime": 1560369030.3201864,
        "dev": 64768,
        "gid": 0,
        "gr_name": "root",
        "inode": 278049,
        "isblk": false,
        "ischr": false,
        "isdir": false,
        "isfifo": false,
        "isgid": false,
        "islnk": false,
        "isreg": true,
        "issock": false,
        "isuid": false,
        "mode": "0644",
        "mtime": 1559836357.0,
        "nlink": 1,
        "path": "/timp2/microcode_ctl-1.17-33.13.el6_10.x86_64.rpm",
        "pw_name": "root",
        "rgrp": true,
        "roth": true,
        "rusr": true,
        "size": 3101056,
        "uid": 0,
        "wgrp": false,
        "woth": false,
        "wusr": true,
        "xgrp": false,
        "xoth": false,
        "xusr": false
    },
    "item.path": "/timp2/microcode_ctl-1.17-33.13.el6_10.x86_64.rpm"
}

So, the find works, hurray for that. However, because I'm new to ansible, I cannot yet see how to use only the item.path or simply "path" as the variable to send to yum. Yum chokes on this massive output as it should.

What am I missing, to make yum only use the line out of the find that I want it to so that yum only gets a list of packages.

I'm trying to avoid using the command or shell module here, but starting to wonder if that is what it will take.

(Redhat, if you're reading this, if ansible is going to support the download only option of yum, making it able to install those patches later without a lot of wrapping and head scratching would be great.)