Convert make rule to ansible - ansible

I have the following in a makefile:
some_file: some_script
bash some_script > $#
and would like to replicate this in an ansible playbook task, where running the task creates the file anew but only if the generating script file has changed, otherwise it's a no-op. Is there any way to accomplish this using the stock ansible modules?

You'd have to execute that in two phases: gather info, then conditionally execute
vars:
files:
- some_file
- some_script
tasks:
- stat: path={{ item }}
register: stats
with_items: '{{ files }}'
- debug:
msg: '{{ stats.results[0].stat.path }} is newer than {{ stats.results[1].stat.path }}'
when: '{{ stats.results[0].stat.mtime > stats.results[1].stat.mtime }}'

Related

How to grab a value from a war file without extracting it preferably, or extracting the minimum amount

I have a .war file called app.war, which contains a test.properties file which has a line called appName: Blackberry. The test.properties file could be anywhere in the WAR file, no specific directory.
What is the most efficient way for me to find the test.properties file, and then grab the value Blackberry from appName: Blackberry which is one of the lines in the file ?
The file looks like this
mainInfo: deployed
app.Name: Blackberry
testRun: success
I have heard about jar xf app.war, but not sure how to approach it. I am very new to Ansible, any help would be really appreciated :).
Regarding your question "How to grab a value from ...", I've created a simple test logic.
---
- hosts: test
become: no
gather_facts: no
vars:
WAR_FILE: "app.war"
PROPERTY_FILE: "test.properties"
tasks:
- name: Gather full path of '{{ PROPERTY_FILE }}', if there is any
shell:
cmd: zipinfo -1 {{ WAR_FILE }} | grep {{ PROPERTY_FILE }}
register: result
check_mode: false
changed_when: false
failed_when: result.rc != 0
- name: Gather content of '{{ PROPERTY_FILE }}'
shell:
cmd: unzip -qq -c {{ WAR_FILE }} {{ result.stdout }}
warn: false
register: properties
check_mode: false
changed_when: false
failed_when: properties.rc != 0
- name: Show content
debug:
msg: "{{ properties.stdout }}"
check_mode: false
... Consider using the unarchive
module rather than running 'unzip'
Resulting into an output of
TASK [Show content] ****
ok: [test.example.com] =>
msg: |-
mainInfo: deployed
app.Name: Blackberry
testRun: success
You have to adapt this to your environment and requirements.
Thanks to
View list of files in ZIP archive on Linux
How can I run unzip silently in terminal
How to unpackage and repackage a WAR file
Linux command for extracting WAR file
Please take note that the result properties.stdout is a list of strings which contains the key values pairs.
- name: Debug how to get value of key
debug:
var: item | type_debug
loop_control:
label: "{{ ansible_loop.index }}"
extended: yes
loop: "{{ properties.stdout_lines }}"
It is recommended to read them into Ansible variables. You will find plenty examples for how to do that here on SO via a search.
- name: Debug how to get value of key
debug:
var: item | from_yaml | type_debug
loop: "{{ properties.stdout_lines }}"
Thanks to
Ansible - Check variable type
Using filters to manipulate data - Formatting data: YAML and JSON

running different script base on extension in Ansible

I have an ansible playbook to run different scripts. I need to change the executable base on the extension. This is my playbook:
- name: run nodejs script
command: node "{{item}}" arg1
loop: "{{ lookup('fileglob', '{{path}}/{{deploy_version}}/*.js', wantlist=True) }}"
- name: running python script
command: python "{{item}}" arg1
loop: "{{ lookup('fileglob', '{{path}}/{{deploy_version}}/*.py, wantlist=True) }}"
Since there is an order to run the scripts, I need to use an "if, else, statement". But I'm unable to find a way to run scripts in alphabetic order based on extension. How can I achieve this?
The splitext filter will extract the extension from the filename, which can then be used to lookup the command in a dict that maps the file extension to the command, and then it can be applied to all the globs you wish, which if I understand correctly you want to run in alphabetical order regardless of which fileglob it matches.
- name: run the scripts
command: '{{ cmd_by_ext[ item|splitext|last ] }} {{ item }} arg1'
loop: '{{ (js_files + py_files) | sort }}'
vars:
script_dir: '{{ path + "/" + deploy_version }}'
js_files: '{{ lookup("fileglob", script_dir+"*/.js", wantlist=True) }}'
py_files: '{{ lookup("fileglob", script_dir+"*/.py", wantlist=True) }}'
cmd_by_ext:
'.js': 'node'
'.py': 'python'

ansible: Looping over directory and referencing that file in another playbook

I am trying to make a playbook that loops over the number of files in a directory and then use those files in another playbook.
My playbook as it is now:
---
- name: Run playbooks for Raji's testing
register: scripts
roles:
- prepare_edge.yml
- prepare_iq.yml
- scriptor.yml
with_fileglob: ~/ansible/test_scripts/*
~
When I run this it doesn't work, I've tried "register: scripts" to make a variable to reference inside scriptor.yml but again the playbook fails. Any advice or help you can provide would be much appreciated.
Thanks!
P.S. I am super new to ansible
here is the scriptor.yml
---
- hosts: all
tasks:
- name: Create directory
command: mkdir /some/path/
- name: If file is a playbook
copy:
src: "{{ scripts }}"
dest: /some/path/
when: "{{ scripts }}" == "*.yml"
- name: if file is a script
shell: . ${{ scripts }}
when: "{{ scripts }}" == "*.sh"
P.S.S prepare_edge.yml and prepare_iq.yml don't reference anything and just need to be called in the loop before scriptor.yml
here is the error:
ERROR! 'register' is not a valid attribute for a Play
The error appears to have been in '/Users/JGrow33/ansible/raji_magic_playbook.yml': line 3, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Run playbooks for Raji's testing
^ here
There error message you're getting is telling you that you can't run register in a Playbook.
You can accomplish what you're looking for by doing something like the following in your scriptor.yml file:
- hosts: all
tasks:
- name: Create directory
command: mkdir /some/path/
- name: If file is a playbook
copy:
src: "{{ item }}"
dest: /some/path/
with_fileglob: ~/ansible/test_scripts/*.yml
- name: if file is a script
shell: . ${{ item }}
with_fileglob: copy:
src: "{{ item }}"
dest: /some/path/
with_fileglobe: ~/ansible/test_scripts/*.sh
References
How can Ansible "register" in a variable the result of including a playbook?

Compare two files with Ansible

I am struggling to find out how to compare two files. Tried several methods including this one which errors out with:
FAILED! => {"msg": "The module diff was not found in configured module paths. Additionally, core modules are missing. If this is a
checkout, run 'git pull --rebase' to correct this problem."}
Is this the best practice to compare two files and ensure the contents are the same or is there a better way?
Thanks in advance.
My playbook:
- name: Find out if cluster management protocol is in use
ios_command:
commands:
- show running-config | include ^line vty|transport input
register: showcmpstatus
- local_action: copy content="{{ showcmpstatus.stdout_lines[0] }}" dest=/poc/files/{{ inventory_hostname }}.result
- local_action: diff /poc/files/{{ inventory_hostname }}.result /poc/files/transport.results
failed_when: "diff.rc > 1"
register: diff
- name: debug output
debug: msg="{{ diff.stdout }}"
Why not using stat to compare the two files?
Just a simple example:
- name: Get cksum of my First file
stat:
path : "/poc/files/{{ inventory_hostname }}.result"
register: myfirstfile
- name: Current SHA1
set_fact:
mf1sha1: "{{ myfirstfile.stat.checksum }}"
- name: Get cksum of my Second File (If needed you can jump this)
stat:
path : "/poc/files/transport.results"
register: mysecondfile
- name: Current SHA1
set_fact:
mf2sha1: "{{ mysecondfile.stat.checksum }}"
- name: Compilation Changed
debug:
msg: "File Compare"
failed_when: mf2sha1 != mf1sha1
your "diff" task is missing the shell keyword, Ansible thinks you want to use the diff module instead.
also i think diff (as name of the variable to register the tasks result) leads ansible to confusion, change to diff_result or something.
code (example):
tasks:
- local_action: shell diff /etc/hosts /etc/fstab
failed_when: "diff_output.rc > 1"
register: diff_output
- debug:
var: diff_output
hope it helps
From Ansible User Guide: https://docs.ansible.com/ansible/latest/user_guide/playbooks_error_handling.html
- name: Fail task when both files are identical
ansible.builtin.raw: diff foo/file1 bar/file2
register: diff_cmd
failed_when: diff_cmd.rc == 0 or diff_cmd.rc >= 2
A slightly shortened version of 'imjoseangel' answer which avoids setting facts:
vars:
file_1: cats.txt
file_2: dogs.txt
tasks:
- name: register the first file
stat:
path: "{{ file_1 }}"
checksum: sha1
get_checksum: yes
register: file_1_checksum
- name: register the second file
stat:
path: "{{ file_2 }}"
checksum: sha1
get_checksum: yes
register: file_2_checksum
- name: Check if the files are the same
debug: msg="The {{ file_1 }} and {{ file_2 }} are identical"
failed_when: file_1_checksum.stat.checksum != file_2_checksum.stat.checksum
ignore_errors: true

Ansible: register content not available for other host

Below is a part of a playbook in Ansible 2.1:
- hosts: localhost
any_errors_fatal: true
tasks:
- name: Bla Bla
file: path=/var/tmp/somedir state=directory
#ignore_errors: no
- name: Create directory for every host
file: path=/var/tmp/somedir/{{ item }} state=directory
with_items: "{{ groups['XYZ'] }}"
- name: Get File contents of NewFile
shell: cat NewFile.txt executable=/bin/bash
register: file_contents
- hosts: XYZ
#any_errors_fatal: true
vars:
num_hosts: "{{ groups['XYZ'] | length }}"
serial: num_hosts
tasks:
- name: Copy files to corresponding directories
vars:
path: /var/tmp/somedir/{{ item[0] }}
synchronize: mode=pull src={{ item[1] }} dest={{ path }}
with_nested:
- "{{ groups['XYZ'] }}"
- with_lines: cat NewFile.txt
This does not work.
Now the problem is i am not able to reference file_contents which has been registered under localhost and Ansible is not supporting to cat the NewFile from the hosts: XYZ
Is there any way to do this in some simple manner? I need to check contents of the NewFile in this playbook only and then use the same to copy files from remote to local.
As mentioned in the comments, facts (or all variables) are stored on a host basis. If you have registered a values from a task running on localhost, you can access it from any task running in context of other hosts through the global hostvars dict. All hosts and their facts are stored in there:
hostvars['localhost']['file_contents']
I am not entirely sure simply registered variables are available in the hostvars dict. If not, you have to use set_fact in the first play to store it as a fact.

Resources