Skip to content

Instantly share code, notes, and snippets.

@bcoca
Created April 25, 2025 14:25
Show Gist options
  • Select an option

  • Save bcoca/ba3d8dc74d52120e8595a8dec50a85c1 to your computer and use it in GitHub Desktop.

Select an option

Save bcoca/ba3d8dc74d52120e8595a8dec50a85c1 to your computer and use it in GitHub Desktop.

Revisions

  1. bcoca created this gist Apr 25, 2025.
    162 changes: 162 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,162 @@
    # This play is an ansibe-pull substitute, will prompt for options or can bypass by passing as extra vars
    - name: ansible-pull
    hosts: localhost
    gather_subset: min
    vars:
    now: >-
    {{ lookup('pipe', 'date +"%F %T"') }}
    vars_prompt:
    - name: repo_url
    prompt: URL of the playbook repository
    private: false
    - name: work_dir
    prompt: The path to the directory into which the repository checkout will be done
    private: false
    - name: repo_action
    prompt: Repository action name, which ansible will use to check out the repo. Choices are 'git', 'subversion', 'hg', 'bzr'.
    default: git
    private: false
    - name: checkout_version
    prompt: branch/tag/commit to checkout. Defaults to behavior of repository module
    private: false
    - name: playbooks
    prompt: Which playbook(s) to run from the checkout directory, if none specified one matchin the current host or 'local.yml' will be attempted.
    private: false
    - name: playbook_options
    prompt: Extra command line options to pass to ansible-playbook
    private: false
    - name: accept_host_key
    prompt: If needed, adds the hostkey for the repo url if not already added
    default: false
    private: false
    - name: private_key_file
    prompt: File with private key required to access the repo, if needed.
    private: false
    - name: only_changed
    prompt: Do you want to only run the playbook if the repository has been updated?
    default: false
    private: false
    - name: sleep
    prompt: >-
    How long should Ansible sleep for random interval (between 0 and n number of seconds) before starting?
    This is a useful way to disperse git requests.
    default: 0
    private: false
    - name: force
    prompt: Run the playbook even if the repo update fails.
    default: false
    private: false
    - name: full_clone
    prompt: Do a full clone, instead of a shallow one
    default: false
    private: false
    - name: verify
    prompt: |-
    Verify GPG signature of checked out commit, if it fails abort running the playbook.
    This needs the corresponding repo action to support such an operation.
    default: false
    private: false
    - name: purge
    prompt: Do you want to purge checkout after playbook run?
    default: false
    private: false
    - name: clean
    prompt: Should modified files in the working repository be discarded
    default: false
    private: false
    - name: track_subs
    prompt: Submodules will track the latest changes. This is equivalent to specifying the --remote flag to git submodule update
    default: false
    private: false
    tasks:
    - name: Ensure I have everything I need
    block:
    - name: The bare minimum needed
    assert:
    that:
    - work_dir is defined
    - repo_url is defined

    # TODO: add vars + values?
    - name: I'm starting!!!
    debug:
    msg: "Starting Pull at {{now}}"

    - name: Do the repo checkout
    block:
    - name: check workdir
    stat:
    path: work_dir
    register: local_workdir

    # ignore permission issues, those will be clear on checkout
    - name: Create, in case repo action cannot
    file:
    path: work_dir
    state: directory
    when: not local_workdir['stat']['exists']

    - name: git pull
    git:
    name: '{{repo_url}}'
    dest: '{{work_dir}}'
    version: '{{checkout_version|default(omit)}}'
    accept_hostkey: '{{accept_host_key}}'
    verify_commit: '{{verify}}'
    depth: '{{fullclone|ternary(omit, 1)}}'
    track_submodules: '{{track_submodules|default(omit)}}'
    key_file: '{{private_key_file|default(omit)}}'
    force: '{{clean|default(omit)}}'
    when: repo_action in ('git',)
    register: checkout
    ignore_errors: '{[force}}'

    - name: other pulls
    fail:
    msg: 'I did not implement {{repo_action}} ... just use git!'
    when: repo_action in ('subversion', 'hg', 'bzr')

    - name: Execute the playbook
    when:
    - not only_changed or only_changed == checkout['changed']
    block:
    - name: get playbooks, since none specified
    set_fact:
    playbooks: "{{ lookup('first_found', files=*candidates, paths=work_dir) }}"
    vars:
    candidates:
    - "{{ansible_facts['fqdn']}}.yml"
    - "{{ansible_facts['hostname']}}.yml"
    - local.yml
    when: playbooks is undefined

    - name: actually do stuff
    shell: ansible-playbook {{playbooks}} {{playbook_options}}
    register: pull_result
    ignore_errors: true

    - name: Cleanup
    when: purge
    block:
    - name: PURGE!
    file:
    path: work_dir
    state: absent
    register: next_day
    ignore_errors: true

    - name: purge thwarted!
    debug:
    msg: 'Unable to purge: {{ next_day["msg"] }}'.
    when: next_day is failed

    - name: Notify/log
    block:
    - name: show results (TODO: add options for mail/im/api call)
    debug:
    var: pull_result

    - name: passthrough failure status for caller (cron/inotify/intern)
    fail:
    msg: playbook execution ended in error
    when: pull_result is failed