Ansible | Variable declaration to bash script - ansible

I have a bash script under files which needs a variable to get passed from default\main1.yml. How can I declare the same?
roles
config
defaults
main1.yml
files
script.sh
tasks
main2.yml
defaults\main1.yml
log_group_name: "{{ lookup('env','LOG_GROUP') }}"
script.sh
for NAME in $(ls -1p /home/ec2-user/ |grep -v "^_" | grep -v "/$" |cut -d. -f1);
do
if ! grep $NAME /etc/awslogs/awslogs.conf;
then
sudo tee -a /etc/awslogs/awslogs.conf << END
[$DAGNAME]
datetime_format = %b %d %H:%M:%S
file = /var/log/airflow/$NAME/*/*/*.log
buffer_duration = 5000
log_stream_name = $NAME
initial_position = start_of_file
log_group_name = ${log_group_name}
END
fi
done
sudo service awslogsd start
sudo systemctl enable awslogsd
task/cloud.yml
---
- name: 'Cloud | AWSlogs.conf file'
when: inventory_hostname == 'master'
script: ../files/cloud.sh
- name: 'Cloud | AWSlogs.conf file'
when: inventory_hostname == 'worker_1'
script: ../files/cloud.sh
ansible command to execute the play:- deploy.py
execute(['sudo', '-E', 'ansible-playbook', 'ansible/plays/deploy.yml', '-i', 'hosts.yml'],
stdout=sys.stdout, stderr=sys.stderr, env=aug_env)

See if this works -
- hosts: localhost
tasks:
- shell: "script.sh {{ log_group_name }}"

You need to set the variable within the execution environment of the script, but it clearly already exists since you're pulling it out of the ENV so you don't even need to do that. If you did, you could install the script via the Ansible template module and execute the script that way.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_environment.html

Simply use the script's parameter
script.sh
log_group_name=$1
...
and run the script with the parameter
roles/config/tasks/main2.yml
- command: "{{ role_path }}/files/script.sh {{ log_group_name }}"
You probably know, but just to be sure. This will work with the "localhost" only. In other cases, the script must be copied to the "remote hosts" first and the path to the script must be changed.

Related

Ansible: check, that file has changed after shell command

I have a shell command in ansible, that changes some file. But most of the time, file stays the same.
What is a preferred way to compare the content of the file before/after shell command and set task changed property?
Q: "Compare the content of the file before/after the shell command and set task changed."
A: Make the script report the changes, register the output of the shell command, and test changed_when.
For example, the task below sets a random environment variable RANDOM_TEXT and writes it to the file /tmp/test.ansible. If the file changes the script will report changed. Because of the potentially failing diff you have to set ignore_errors: true
- shell: "sh -c 'cp /tmp/test.ansible /tmp/test.ansible.orig;
echo $RANDOM_TEXT > /tmp/test.ansible;
if (diff /tmp/test.ansible.orig /tmp/test.ansible > /dev/null);
then echo not changed;
else echo changed;
fi'"
environment:
RANDOM_TEXT: "{{ lookup('random_choice', 'AAA', 'BBB') }}"
ignore_errors: true
register: result
changed_when: result.stdout == 'changed'
Example of a complete playbook for testing
- hosts: localhost
tasks:
- shell: "sh -c 'cp /tmp/test.ansible /tmp/test.ansible.orig;
echo $RANDOM_TEXT > /tmp/test.ansible;
if (diff /tmp/test.ansible.orig /tmp/test.ansible > /dev/null);
then echo not changed;
else echo changed;
fi'"
environment:
RANDOM_TEXT: "{{ lookup('random_choice', 'AAA', 'BBB') }}"
ignore_errors: true
register: result
changed_when: result.stdout == 'changed'
- debug:
var: result

Convering If-else shell to Ansible

I am trying to convert this command to Ansible script. But I am not getting any luck. When module will not help.
if [ ${EnvType} == "PRE" ]
then
EnvPrefix="RP"
else
EnvPrefix=$(echo "${EnvType}" | cut -c1,3)
fi
export EnvPrefix
Essentially i need to export envprefix based on envtype. I can run shell command to findout if envtype is pre but I am receiving blank when i try to export using shell module.
- name: Set Envprefix for other environment
shell: |
EnvPrefix=$(echo "${EnvType}" | cut -c1,3)
export EnvPrefix
when: output.stdout != "PRE"
This is the equivalent
- set_fact:
EnvPrefix: "{{ (EnvType == 'PRE')|
ternary('ST',[EnvType.0,EnvType.2]|join) }}"
- command: "export {{ EnvPrefix }}"
In case the list of the selections is longer, map/extract might be more efficient
- set_fact:
EnvPrefix: "{{ (EnvType == 'PRE')|
ternary('ST',[0,2]|map('extract',EnvType)|list|join) }}"

How to put variable in bash script with ansible playbook

I need a put variable in script with an Ansible playbook. I get the variable from Jenkins 'build with parameter' but I can't put a " tag " variable in my script. How can I do that?
This is my script:
export JAVA_HOME=/home/asd/products/app/java8
tag=$(tag)
hzpid=$(ps aux |grep /home/asd/products/app/hzcluster/ |grep -v grep | awk '{print $2}' | sed -r 's/%/ /g')
echo $hzpid
if [[ -z $hzpid ]]; then
echo "no running applications"
else
kill -9 $hzpid && echo "running process terminated."
fi
nohup $JAVA_HOME/bin/java -Dspring.profiles.active=dxl-dev -jar /home/asd/products/app/hzcluster/new/hzcluster-$tag-SNAPSHOT.jar > $LOG_DIR/hzcluster.log &
exit 0
This is my ansible-playbook:
- hosts: '{{ hosts }}'
gather_facts: no
tasks:
- name: Run new hzcluster.jar
shell: sh '{{ sh_file }}'start-hzcluster2.sh '{{ tag }}'
In your shell script change from tag=$(tag) to tag=$1
Playbook:
- hosts: '{{ hosts }}'
gather_facts: no
tasks:
- name: Run new hzcluster.jar
shell: sh '{{ sh_file }}'start-hzcluster2.sh '{{ tag }}'

Write to file specified by user from command line argument - Ansible

I am trying to write a line to a file using lineinfile.
The name of the file is to be passed to the playbook at run time by the user as a command line argument.
Here is what the task looks like:
# Check for timezone.
- name: check timezone
tags: timezoneCheck
register: timezoneCheckOut
shell: timedatectl | grep -i "Time Zone" | awk --field-separator=":" '{print $2}' | awk --field-separator=" " '{print $1}'
- lineinfile:
path: {{ output }}
line: "Did not find { DesiredTimeZone }"
create: True
state: present
insertafter: EOF
when: timezoneCheckOut.stdout != DesiredTimezone
- debug: var=timezoneCheckOut.stdout
My questions are:
1. How do I specify the command line argument to be the destination file to write to (path)?
2. How do I append the argument DesiredTimeZone (specified in an external variables file) to the line argument?
My following answer might not be your solutions.
how to specify the command argument for output variable.
ansible-playbook yourplaybook.yml -e output=/path/to/outputfile
how to include DesiredTimeZone variable from external file.
vars_files:
- external.yml
full playbook.yml for testing on local:
yourplaybook.yml
- name: For testing
hosts: localhost
vars_files:
- external.yml
tasks:
- name: check timezone
tags: timezoneCheck
register: timezoneCheckOut
shell: timedatectl | grep -i "Time Zone" | awk -F":" '{print $2}' | awk --field-separator=" " '{print $1}'
- debug: var=timezoneCheckOut.stdout
- lineinfile:
path: "{{ output }}"
line: "Did not find {{ DesiredTimeZone }}"
create: True
state: present
insertafter: EOF
when: timezoneCheckOut.stdout != DesiredTimeZone
external.yml (place the same level with yourplaybook.yml)
---
DesiredTimeZone: "Asia/Tokyo"
With Ansible you should define the desired state. Period.
The correct way of doing this is to just use timezone module:
- name: set timezone
timezone:
name: "{{ DesiredTimeZone }}"
No need to jump through the hoops with shell, register, compare, print...
If you want to put system into the desired state, just run playbook:
ansible-playbook -e DesiredTimeZone=Asia/Tokyo timezone_playbook.yml
Ansible will ensure that all hosts in question will have the DesiredTimeZone.
If you just want to check if you system comply to desired state, use --check switch:
ansible-playbook -e DesiredTimeZone=Asia/Tokyo --check timezone_playbook.yml
In this case Ansible will just print to the log what should be changed in the current state to become desired state and don't make any actual changes.

Ansible playbook shell output

I would like to quickly monitor some hosts using commands like ps,dstat etc using ansible-playbook. The ansible command itself perfectly does what I want, for instance I'd use:
ansible -m shell -a "ps -eo pcpu,user,args | sort -r -k1 | head -n5"
and it nicely prints all std output for every host like this:
localhost | success | rc=0 >>
0.0 root /sbin/init
0.0 root [kthreadd]
0.0 root [ksoftirqd/0]
0.0 root [migration/0]
otherhost | success | rc=0 >>
0.0 root /sbin/init
0.0 root [kthreadd]
0.0 root [ksoftirqd/0]
0.0 root [migration/0]
However this requires me to keep a bunch of shell scripts around for every task which is not very 'ansible' so I put this in a playbook:
---
-
hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
and run it with -vv, but the output baiscally shows the dictionary content and newlines are not printed as such so this results in an unreadable mess like this:
changed: [localhost] => {"changed": true, "cmd": "ps -eo pcpu,user,args | sort -r -k1
head -n5 ", "delta": "0:00:00.015337", "end": "2013-12-13 10:57:25.680708", "rc": 0,
"start": "2013-12-13 10:57:25.665371", "stderr": "", "stdout": "47.3 xxx Xvnc4 :24
-desktop xxx:24 (xxx) -auth /home/xxx/.Xauthority -geometry 1920x1200\n
....
I also tried adding register: var and the a 'debug' task to show {{ var.stdout }} but the result is of course the same.
Is there a way to get nicely formatted output from a command's stdout/stderr when run via a playbook? I can think of a number of possible ways (format output using sed? redirect output to file on the host then get that file back and echo it to the screen?), but with my limited knowledge of the shell/ansible it would take me a day to just try it out.
The debug module could really use some love, but at the moment the best you can do is use this:
- hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
register: ps
- debug: var=ps.stdout_lines
It gives an output like this:
ok: [host1] => {
"ps.stdout_lines": [
"%CPU USER COMMAND",
" 1.0 root /usr/bin/python",
" 0.6 root sshd: root#notty ",
" 0.2 root java",
" 0.0 root sort -r -k1"
]
}
ok: [host2] => {
"ps.stdout_lines": [
"%CPU USER COMMAND",
" 4.0 root /usr/bin/python",
" 0.6 root sshd: root#notty ",
" 0.1 root java",
" 0.0 root sort -r -k1"
]
}
This is a start may be :
- hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
register: ps
- local_action: command echo item
with_items: ps.stdout_lines
NOTE: Docs regarding ps.stdout_lines are covered here: ('Register Variables' chapter).
Expanding on what leucos said in his answer, you can also print information with Ansible's humble debug module:
- hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
register: ps
# Print the shell task's stdout.
- debug: msg={{ ps.stdout }}
# Print all contents of the shell task's output.
- debug: var=ps
I found using the minimal stdout_callback with ansible-playbook gave similar output to using ad-hoc ansible.
In your ansible.cfg (Note that I'm on OS X so modify the callback_plugins path to suit your install)
stdout_callback = minimal
callback_plugins = /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ansible/plugins/callback
So that a ansible-playbook task like yours
---
-
hosts: example
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
Gives output like this, like an ad-hoc command would
example | SUCCESS | rc=0 >>
%CPU USER COMMAND
0.2 root sshd: root#pts/3
0.1 root /usr/sbin/CROND -n
0.0 root [xfs-reclaim/vda]
0.0 root [xfs_mru_cache]
I'm using ansible-playbook 2.2.1.0
ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook /tmp/foo.yml -vvv
Tasks with STDOUT will then have a section:
STDOUT:
What ever was in STDOUT
If you need a specific exit status, Ansible provides a way to do that via callback plugins.
Example. It's a very good option if you need a 100% accurate exit status.
If not, you can always use the Debug Module, which is the standard for this cases of use.
Cheers
for me, the only one that works (because of register+with_items combination) is this:
- name: "download and distribute certs"
shell: "python3 /tmp/bla.py {{ item.name }}"
register: python3
with_items: "{{ my_list }}"
- debug: msg="{{ item.stdout_lines | join("\n") }}"
with_items: "{{ python3['results'] }}"
I personally have several shell or command calls in a playbook and gather that's output to different variables. At the end I sum up the information and list all at once like so:
- ansible.builtin.shell: "df -h"
register: disk
- ansible.builtin.shell: "free -m"
register: mem
.....
- name: Summarize
local_action: ansible.builtin.debug var={{ item }}
become: no
with_items:
- disk.stdout_lines
- mem.stdout_lines
if you call it with
ANSIBLE_STDOUT_CALLBACK=minimal ansible-playbook getServerInfo.yml
it gives a nice, clean output
Perhaps not relevant if you're looking to do this ONLY using ansible. But it's much easier for me to have a function in my .bash_profile and then run _check_machine host1 host2
function _check_machine() {
echo 'hostname,num_physical_procs,cores_per_procs,memory,Gen,RH Release,bios_hp_power_profile,bios_intel_qpi_link_power_management,bios_hp_power_regulator,bios_idle_power_state,bios_memory_speed,'
hostlist=$1
for h in `echo $hostlist | sed 's/ /\n/g'`;
do
echo $h | grep -qE '[a-zA-Z]'
[ $? -ne 0 ] && h=plabb$h
echo -n $h,
ssh root#$h 'grep "^physical id" /proc/cpuinfo | sort -u | wc -l; grep "^cpu cores" /proc/cpuinfo |sort -u | awk "{print \$4}"; awk "{print \$2/1024/1024; exit 0}" /proc/meminfo; /usr/sbin/dmidecode | grep "Product Name"; cat /etc/redhat-release; /etc/facter/bios_facts.sh;' | sed 's/Red at Enterprise Linux Server release //g; s/.*=//g; s/\tProduct Name: ProLiant BL460c //g; s/-//g' | sed 's/Red Hat Enterprise Linux Server release //g; s/.*=//g; s/\tProduct Name: ProLiant BL460c //g; s/-//g' | tr "\n" ","
echo ''
done
}
E.g.
$ _machine_info '10 20 1036'
hostname,num_physical_procs,cores_per_procs,memory,Gen,RH Release,bios_hp_power_profile,bios_intel_qpi_link_power_management,bios_hp_power_regulator,bios_idle_power_state,bios_memory_speed,
plabb10,2,4,47.1629,G6,5.11 (Tikanga),Maximum_Performance,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
plabb20,2,4,47.1229,G6,6.6 (Santiago),Maximum_Performance,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
plabb1036,2,12,189.12,Gen8,6.6 (Santiago),Custom,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
$
Needless to say function won't work for you as it is. You need to update it appropriately.

Resources