Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Ansible unarchive be made to write static folder modification times?

I am writing a build process for a WordPress installation using Ansible. It doesn't have a application-level build system at the moment, and I've chosen Ansible so that it can cleanly integrate with server build scripts, so I can bring up a working server at the touch of a button.

Most of my WordPress plugins are being installed with the unarchive feature, pointing to versioned plugin builds on the official wordpress.org installation server. I've encountered a problem with just one of these, which is that it is always being marked as "changed" even though the files are exactly the same.

Having examined the state of ls -Rl before and after, I noticed that this plugin (WordPress HTTPS) is the only one to use internal sub-directories, and upon each decompression, the modification time of folders is getting bumped.

It may be useful to know that this is a project build script, with a connection of local. I guess therefore that means that SSH is not being used.

Here is a snippet of my playbook:

- name: Install the W3 Total Cache plugin
  unarchive: >
    src=https://downloads.wordpress.org/plugin/w3-total-cache.0.9.4.1.zip
    dest=wp-content/plugins
    copy=no

- name: Install the WP DB Manager plugin
  unarchive: >
    src=https://downloads.wordpress.org/plugin/wp-dbmanager.2.78.1.zip
    dest=wp-content/plugins
    copy=no

# @todo Since this has internal sub-folders, need to work out
# how to preserve timestamps of the original folders rather than
# re-writing them, which forces Ansible to record a change of
# server state.
- name: Install the WordPress HTTPS plugin
  unarchive: >
    src=https://downloads.wordpress.org/plugin/wordpress-https.3.3.6.zip
    dest=wp-content/plugins
    copy=no

One hacky way of fixing this is to use ls -R before and after, using options to include file sizes but not timestamps, and then md5sum that output. I could then mark it as changed if there is a change in checksum. It'd work but it's not very elegant (and I'd want to do that for all plugins, for consistency).

Another approach is to abandon the task if a plugin file already exists, but that would cause problems when I bump the plugin version number to the latest copy.

Thus, ideally, I am looking for a switch to present to unarchive to say that I want the folder modification times from the zip file, not from playbook runtime. Is it possible?


Update: a commenter asked if the file contents could have changed in any way. To determine whether they have, I wrote this script, which creates a checksum for (1) all file contents and (2) all file/directory timestamps:

#!/bin/bash

# Save pwd and then change dir to root location
STARTDIR=`pwd`
cd `dirname $0`/../..

# Clear collation file
echo > /tmp/wp-checksum

# List all files recursively
find wp-content/plugins/wordpress-https/ -type f | while read file
do
    #echo $file
    cat $file >> /tmp/wp-checksum
done

# Get checksum of file contents
sha1sum /tmp/wp-checksum

# Get checksum of file sizes
ls -Rl wp-content/plugins/wordpress-https/ | sha1sum

# Go back to original dir
cd $STARTDIR

I ran this as part of my playbook (running it in isolation using tags) and received this:

PLAY [Set this playbook to run locally] ****************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [jonblog : Run checksum command] ******************************************
changed: [localhost]

TASK [jonblog : debug] *********************************************************
ok: [localhost] => {
    "checksum_before.stdout_lines": [
        "374fadc4df1578f78fd60b1be6758477c2c533fa  /tmp/wp-checksum", 
        "10d66f7bdbbdd3af531d1b11a3db3059a5868838  -"
    ]
}

TASK [jonblog : Install the WordPress HTTPS plugin] ***************
changed: [localhost]

TASK [jonblog : Run checksum command] ******************************************
changed: [localhost]

TASK [jonblog : debug] *********************************************************
ok: [localhost] => {
    "checksum_after.stdout_lines": [
        "374fadc4df1578f78fd60b1be6758477c2c533fa  /tmp/wp-checksum", 
        "719c9da94b525e723b1abe188ee9f5bbaf121f3f  -"
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=6    changed=3    unreachable=0    failed=0   

The debug lines reflect the checksum hash of the contents of the files (this is identical) and then the checksum hash of ls -Rl of the file structure (this has changed). This is in keeping with my prior manual finding that directory checksums are changing.

So, what can I do next to track down why folder modification times are incorrectly flagging this operation as changed?

like image 372
halfer Avatar asked Jun 05 '16 20:06

halfer


2 Answers

Rather than overwriting all files each time and find a way to keep the same modification datetime, you may want to use the creates option of the unarchive module.

As you maybe already know, this tells Ansible that a specific file/folder will be created as a result of the task. Thus, next time the task will not be run again if that file/folder already exists.

See http://docs.ansible.com/ansible/unarchive_module.html#options

like image 160
Francesco Abeni Avatar answered Sep 21 '22 03:09

Francesco Abeni


My solution is to modify the checksum script and to make that a permanent feature of the Ansible process. It feels a bit hacky to do my own checksumming, when Ansible should do it for me, but it works.

New answers that explain that I am doing something wrong, or that a new version of Ansible fixes the problem, would be most welcome.

If I get a moment, I will raise this as a possible bug with the Ansible team. However I do sometimes wonder about the effort/reward ratio when raising bugs on a busy tracker - I already have one item outstanding, it has been waiting a while, and I've chosen to work around that too.

Update (18 months later)

This Ansible build system never made it into live. It felt like I was always working around something. Recently, when I decided I needed to move my blog to another server, I finally Dockerised it. This took several weeks (since there is a surprising amount of things to think about in a real WordPress installation) but in general I found the process much nicer than using orchestration tools.

like image 37
halfer Avatar answered Sep 20 '22 03:09

halfer