Git module: don't pull when the clone is already up-to-date.

Hi all,

I’m using ansible to manage a couple of django apps. In particular I’m using the git module to get a clone of these apps in the production machines.
If you don’t know django, the configuration of the entire web application is saved in a file (named settings.py) that is usually committed along all the code.

For a lot of reasons i keep two different settings.py files:

  1. The one committed in the git repo is the one containing the settings using during development.
  2. For the production machine I have a different settings.py, not committed and manage separately (it contains all the passwords for databases, API keys for other service and other stuff that don’t belong in the main repo).

So, i run a playbook like this:

  • name: Clone the repository
    git: repo=…
    dest=/path/to/clone
    version=master
    force=yes
    notify:

  • django manage collectstatic

  • django manage south migrate

  • restart uWSGI

  • name: Upload production settings.py (this will overwrite the dev one from the repo)
    template: src=settings.py.j2
    dest=/path/to/clone/settings.py
    owner=root
    group=root
    mode=0644

That works fine but it does have a problem.
If I run the playbook a second time the git task will always pull the repository overwriting the production settings.py uploaded the first time, even when the clone is already up-to-date.
Here’s the verbose output for the task:

TASK: [box | Clone the repository] ************************************
changed: [vagrant_home_server] => {“after”: “0d7a146a6eadd279218c1305d400d6058d17f26f”, “before”: “0d7a146a6eadd279218c1305d400d6058d17f26f”, “changed”: true, “item”: “/path/to/clone”, “msg”: “Local modifications exist”}

You can see that the target repo is already up-to-date but the task has pulled the code overwriting the productions settings.py. This will also trigger the tasks under the notify, in particular the restart uWSGI one that shouldn’t be executed every time.

So my question is: it is possible to keep the force=yes behavior, but pulling only when really needed?

Best regards,
EP

Try using something other than 'master' as a version,

version=0d7a146a6eadd279218c1305d400d6058d17f26f

for example.

Thanks for the reply.

I’ve tried using the commit hash as argument for version, but it doesn’t work: it has the same effect of version=master.

“I’ve tried using the commit hash as argument for version, but it doesn’t work: it has the same effect of version=master.”

By same effect you mean it does the pull every time, rather than it checks out master, I’d assume? :slight_smile:

I’d like to see the “-v” output in that case.

(Also note, in regard to the suggestion of using the SHA, I don’t really care for that approach as it’s hard to remember SHAs, you could also use a tag rather than the SHA)

–Michael

You could rename your development settings.py to settings.py.sample, continue to keep it under version control, and add settings.py itself to your .gitignore. This is what Rails does with things like database.yml, which may contain passwords.

“I’ve tried using the commit hash as argument for version, but it doesn’t work: it has the same effect of version=master.”

By same effect you mean it does the pull every time, rather than it checks out master, I’d assume? :slight_smile:

I’d like to see the “-v” output in that case.

(Also note, in regard to the suggestion of using the SHA, I don’t really care for that approach as it’s hard to remember SHAs, you could also use a tag rather than the SHA)

–Michael

The verbose output using the commit hash as version is the same one that I get with version=master: the one returned by this.

And, looking at the source, this is what I think happens (starting from here):

  1. local_mods is True (there’s the settings.py file with the production settings).
  2. I have forced=True and I am not doing a dry run, so the reset --HARD is executed reverting the settings.py to the one in the repo (the devel one).
  3. before == remote_head evaluates to true and the module exits with the message linked above.

My problem is the 2. The reset is always executed, even when before == remote_head.

You could rename your development settings.py to settings.py.sample, continue to keep it under version control, and add settings.py itself to your .gitignore. This is what Rails does with things like database.yml, which may contain passwords.

Nice idea. I could use a settings.py with generic and development settings kept under git, and a separate production_settings.py, excluded by .gitignore, with the production settings.
To make everything work I just need to add something like:

try:
import production_settings
except ImportError:
pass

at the end of the settings.py file.

Thanks

Best regards,
EP