Ansible inventory same server in multiple groups, execute a task multiple times - ansible

I have Ansible inventory as below:
[all]
[zookeeper]
host1
host2
host3
[broker]
host1
host2
host3
host4
[schemaregistry]
host2
host3
[ksql]
host5
host6
[connector]
host4
[restproxy]
host5
host6
[controlcenter]
host1
The group names are services installed on a server. A server can have more that one service installed. Through my playbook I expect to execute task of only one server group. For example, when I limit the playbook execute of server group [controlcenter] which has host1, the execution is done for other group also which has host1 in them.
How can I avoid this behavior?
ansible-playbook certificate_expiry_calculator.pb -i /home/ansible/inv_dev.yml -l controlcenter
this gives me results for controlcenter as well as for broker and zookeeper.
The playbook is
# FOR SIT
#
# source /home/ansible/highlight.sh;ansible-playbook /home/ansible/certificate_expiry_calculator.pb -i /home/ansible/inv_sit.yml |grep msg| sed 's/\\n/\n/g'|sed 's/\\r//g'|sed 's/\\t/ /'|sed 's/"msg": "//g'|sed 's/"//g'|sed 's/^ //g'|column -t|highlight red `date +%Y`|sed "s/^/ /"
# FOR DEV
#
# source /home/ansible/highlight.sh;ansible-playbook /home/ansible/certificate_expiry_calculator.pb -i /home/ansible/inv_dev.yml |grep msg| sed 's/\\n/\n/g'|sed 's/\\r//g'|sed 's/\\t/ /'|sed 's/"msg": "//g'|sed 's/"//g'|sed 's/^ //g'|column -t|highlight red `date +%Y`|sed "s/^/ /"
- hosts: broker
tasks:
- name: calculate keystore expiry for broker
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/kafka/server.properties|grep keystore.location|cut -d "=" -f2|head -1`
#keystore_pwd=`cat /etc/kafka/server.properties|grep ssl.keystore.password|cut -d "=" -f2|head -1`
keystore_pwd="zzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "BROKER : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "BROKER : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
- hosts: zookeeper
tasks:
- name: calculate keystore expiry for zookeeper
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/kafka/zookeeper.properties|grep keyStore.location|cut -d "=" -f2|head -1`
#keystore_pwd=`cat /etc/kafka/zookeeper.properties|grep ssl.keystore.password|cut -d "=" -f2|head -1`
keystore_pwd="zzzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "ZOOKEEPER : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "ZOOKEEPER : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
- hosts: connector
tasks:
- name: calculate keystore expiry for connector
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/kafka/connect-distributed.properties|grep keystore.location|cut -d "=" -f2|head -1`
#keystore_pwd=`cat /etc/kafka/connect-distributed.properties|grep ssl.keystore.password|cut -d "=" -f2`
keystore_pwd="zzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "CONNECTOR : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "CONNECTOR : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
- hosts: controlcenter
tasks:
- name: calculate keystore expiry for control center
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/confluent-control-center/control-center-production.properties|grep keystore.location|cut -d "=" -f2|head -n 1`
#keystore_pwd=`cat /etc/confluent-control-center/control-center-production.properties|grep keystore.password|cut -d "=" -f2|head -n 1`
keystore_pwd="zzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "CONTROL_CENTER : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "CONTROL_CENTER : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
- hosts: schemaregistry
tasks:
- name: calculate keystore expiry for schema_registry
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/schema-registry/schema-registry.properties|grep keystore.location|cut -d "=" -f2`
#keystore_pwd=`cat /etc/schema-registry/schema-registry.properties|grep ssl.keystore.password|cut -d "=" -f2`
keystore_pwd="zzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "SCHEMA_REGISTRY : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "SCHEMA_REGISTRY : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
- hosts: restproxy
tasks:
- name: calculate keystore expiry for rest proxy
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/kafka-rest/kafka-rest.properties|grep keystore.location|cut -d "=" -f2|head -n 1`
#keystore_pwd=`cat /etc/kafka-rest/kafka-rest.properties|grep ssl.keystore.password|cut -d "=" -f2|head -n 1`
keystore_pwd="zzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "REST_PROXY : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "REST_PROXY : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
- hosts: ksql
tasks:
- name: calculate keystore expiry for rest proxy
become: yes
become_user: root
shell: |
keystore_location=`cat /etc/ksqldb/ksql-server.properties|grep -i ssl.keystore.location|cut -d "=" -f2|head -n 1`
#keystore_pwd=`cat /etc/kafka-rest/ksql-server.properties|grep ssl.keystore.password|cut -d "=" -f2|head -n 1`
keystore_pwd="zzz"
/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd 2>/dev/null | grep Alias | awk '{print $3}' | while read ALIAS
do
EXPIRACY=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null| grep Valid`
UNTIL=`/usr/bin/keytool -list -v -keystore $keystore_location -storepass $keystore_pwd -alias $ALIAS 2>/dev/null | grep Valid | perl -ne 'if(/until: (.*?)\n/) { print "$1\n"; }'`
UNTIL_SECONDS=`date -d "$UNTIL" +%s`
UNTIL_DATE=`echo $UNTIL|sed 's/ /-/g'`
REMAINING_DAYS=$(( ($UNTIL_SECONDS - $(date +%s)) / 60 / 60 / 24 ))
THRESHOLD=`date -d "\`date -d "+90 days"\`" +%s`
if [[ $THRESHOLD -le $UNTIL_SECONDS ]]; then
#printf "${BRIGHT}${GREEN}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n" >> ../certificate_expiry_dates
printf "KSQL : `hostname` : ${BRIGHT}[OK] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
else
printf "KSQL : `hostname` : ${BRIGHT}${RED}[WARNING] : Certificate $ALIAS expires $UNTIL_DATE : days left $REMAINING_DAYS ${NORMAL}\n"
RET=1
fi
done
register: output
- debug:
msg="{{output.stdout}}"
the execution result is
ansible#host1[~] $ source /home/ansible/highlight.sh;ansible-playbook /home/ansible/certificate_expiry_calculator.pb -i /home/ansible/inv_dev.yml --limit controlcenter
PLAY [broker] *****************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************
ok: [host1]
TASK [calculate keystore expiry for broker] ***********************************************************************************
changed: [host1]
TASK [debug] ******************************************************************************************************************
ok: [host1] => {
"msg": "BROKER : host1 : [OK] : Certificate caroot expires Wed-Dec-03-17:49:33-UKT-2042 : days left 7231 \nBROKER : host1 : [OK] : Certificate localhost expires Thu-Dec-12-09:34:06-UKT-2024 : days left 665 "
}
PLAY [zookeeper] **************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************
ok: [host1]
TASK [calculate keystore expiry for zookeeper] ********************************************************************************
changed: [host1]
TASK [debug] ******************************************************************************************************************
ok: [host1] => {
"msg": "ZOOKEEPER : host1 : [OK] : Certificate caroot expires Wed-Dec-03-17:49:33-UKT-2042 : days left 7231 \nZOOKEEPER : host1 : [OK] : Certificate localhost expires Thu-Dec-12-09:34:06-UKT-2024 : days left 665 "
}
PLAY [connector] **************************************************************************************************************
skipping: no hosts matched
PLAY [controlcenter] **********************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************
ok: [host1]
TASK [calculate keystore expiry for control center] ***************************************************************************
changed: [host1]
TASK [debug] ******************************************************************************************************************
ok: [host1] => {
"msg": "CONTROL_CENTER : host1 : [OK] : Certificate caroot expires Wed-Dec-03-17:49:33-UKT-2042 : days left 7231 \nCONTROL_CENTER : host1 : [OK] : Certificate localhost expires Thu-Dec-12-09:34:06-UKT-2024 : days left 665 "
}
PLAY [schemaregistry] *********************************************************************************************************
skipping: no hosts matched
PLAY [restproxy] **************************************************************************************************************
skipping: no hosts matched
PLAY [ksql] *******************************************************************************************************************
skipping: no hosts matched
PLAY RECAP ********************************************************************************************************************
host1 : ok=9 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
As per my understanding play for broker & zookeeper shouldn't have been executed here.

the execution is done for other group also which has host1 in them.
Given the zoo.ini
[all]
[zookeeper]
host1
host2
host3
[broker]
host1
host2
host3
host4
[schemaregistry]
host2
host3
[ksql]
host5
host6
[connector]
host4
[restproxy]
host5
host6
[controlcenter]
host1
a minimal example playbook zoo.yml
---
- hosts: all
become: false
gather_facts: false
tasks:
- debug:
msg: "{{ inventory_hostname }} in {{ group_names }}"
called with
sshpass -p ${PWD} ansible-playbook --inventory zoo.ini --user ${USER} --ask-pass zoo.yml --limit 'controlcenter'
I expect to execute task of only one server group.
will result into the expected output of
TASK [debug] **********************************************
ok: [host1] =>
msg: host1 in [u'broker', u'controlcenter', u'zookeeper']
How can I avoid this behavior?
The execution is done for the given host and group only. For me it was not possible to reproduce an issue.
With the now given playbook and since you are using several - hosts: sections with hard-coded group names, you are actually not targeting hosts and groups with patterns. According Playbook execution you have more than one play.
The issue is reproducible with the following example
---
- hosts: all
become: false
gather_facts: false
tasks:
- debug:
msg: "{{ inventory_hostname }} in {{ group_names }}"
- hosts: broker
become: false
gather_facts: false
tasks:
- debug:
msg: "{{ inventory_hostname }} in {{ group_names }}"
resulting into an output of
PLAY [all] ************************************************
TASK [debug] **********************************************
ok: [host1] =>
msg: host1 in [u'broker', u'controlcenter', u'zookeeper']
PLAY [broker] *********************************************
TASK [debug] **********************************************
ok: [host1] =>
msg: host1 in [u'broker', u'controlcenter', u'zookeeper']
PLAY RECAP ************************************************
host1 : ok=2
How can I avoid this behavior?
In this case I like to recommend to address the playbook structure itself (annot.: and as it seems to be far away from good readable, maintainable, best practices, idempotency, etc.).

I was able to solve this using simple tags for each server group inside playbook. May be another dirty method, but for now it has worked.

Related

How to create a granular bash script with multiple variables with ssh connections

I have the below script:
bash Script:
#!/bin/bash
###########
printf "\n"
marker=$(printf "%0.s-" {1..60})
printf "|$marker|\n"
printf "|%-10s | %-13s | %-29s |\n" "Hostname" "RedHat Vesrion" "Perl Version"
printf "|$marker|\n"
remote_connect() {
target_host=$1
marker=$(printf "%0.s-" {1..60})
rhelInfo=$(ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no cat /etc/redhat-release| awk 'END{print $7}')
perlInfo=$(ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no "rpm -qa | grep -i mod_perl")
if [[ $? -eq 0 ]]
then
printf "|%-10s | %-13s | %-20s |\n" "$target_host" "$rhelInfo" "$perlInfo"
else
printf "|%-10s | %-13s | %-20s |\n" "$target_host" "Unable to get the ssh connection"
fi
} 2>/dev/null
export -f remote_connect
< /home/zabbix/hostsList.txt xargs -P30 -n1 -d'\n' bash -c 'remote_connect "$#"' --
The above script runs pretty well for me while running in parallel mode.
Script results:
|------------------------------------------------------------|
|Hostname | RedHat Vesrion | Perl Version |
|------------------------------------------------------------|
|foxnl41 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl84 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl42 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl63 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl10 | 6.7 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl55 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl95 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
|foxnl85 | 6.9 | mod_perl-2.0.4-11.el6_5.x86_64 |
Concern ?
I have two variables: rhelInfo and perlInfo to get store information. But it is using two ssh calls to the servers to get the values.
Could I have only one SSH call to execute multiple commands and set both variables?
Could I have only one SSH call to execute multiple commands and set both variables?
Sure. You could do:
# this looks too long - so a function
_ssh() {
ssh -i /home/zabbix/.ssh/ssh_key \
-o StrictHostKeyChecking=no \
-o PasswordAuthentication=no \
"root#$target_host" \
"$#"
}
export -f _ssh
# the function to-be-executed on the remote
remotework() {
rhelinfo=$(awk 'END{print $7}' /etc/redhat-release)
perlinfo=$(rpm -qa | grep -i mod_perl)
# output elements separated by byte 0x01
printf "%s\001" "$rhelinfo" "$perlinfo"
}
export -f remotework
remote_connect() {
# execute bash on the remote
# with `remotework` function serialized
# and execute the `remotework` function
# properly `printf %q` quote everything for unquoting done by ssh+remote shell
tmp=$( _ssh "$(printf "%q " bash -c "$(declare -f remotework); remotework")" )
# split the output of ssh by byte 0x01
{
IFS= read -d $'\x01' -r rhelInfo &&
IFS= read -d $'\x01' -r perlInfo
} <<<"$tmp"
}
or similar variation of it. Basically ssh gives you a bidirection stream of data - you can stream anything with a separator in between ("custom protocol") and then split the data on that separator. I.e. the problem is not limited to ssh - research data serialization/deserialization in bash. Above I have chosen the byte 0x01 to be the separator - you can use a separate line with unique uuid, use base64 -w0 to convert data to a single line, or similar or use another format.
remotework() {
awk ... | base64 -w0
echo ' '
rpm ... | base64 -w0
echo
}
...
IFS=' ' read -r rhelInfo perlInfo <<<"$tmp"
rhelInfo=$(<<<"$rhelInfo" base64 -d)
perlInfo=$(<<<"$perlInfo" base64 -d)
You can also serialize variables with declare -p and then eval them - this is in my opinion more dangerous, so it's better to use a separator.
Suggesting to replace following lines:
rhelInfo=$(ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no cat /etc/redhat-release| awk 'END{print $7}')
perlInfo=$(ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no "rpm -qa | grep -i mod_perl")
if [[ $? -eq 0 ]]; then
printf "|%-10s | %-13s | %-20s |\n" "$target_host" "$rhelInfo" "$perlInfo"
else
printf "|%-10s | %-13s | %-20s |\n" "$target_host" "Unable to get the ssh connection"
fi
With following lines:
sshResponseArr=( $(ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no "awk 'END{print}' /etc/redhat-release; rpm -aq|grep -i mod_perl") )
if [[ $? -eq 0 ]]; then
printf "|%-10s | %-13s | %-20s |\n" "$target_host" "${sshResponseArr[6]}" "${sshResponseArr[8]}"
else
printf "|%-10s | %-13s | %-20s |\n" "$target_host" "Unable to get the ssh connection"
fi
Explanation
First I call multi-line commands in the ssh request. Placing all the commands in a single argument with " (as you did).
The real trick is to read multi-line ssh response into bash array variable sshResponseArr
By default the array is parsed by spaces.
I assume (as you did) that words positioning in the array is consistent across all hosts therefore:
$rhelInfo is ${sshResponseArr[6]}
And $perlInfo is ${sshResponseArr[8]}
Alternative conservative handling of sshResponseArr as an array of 2 lines response from ssh command:
mapfile -t sshResponseLinesArr < <(ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no "awk 'END{print}' /etc/redhat-release; rpm -aq|grep -i mod_perl")
lastLineInReleaseFile=${sshResponseLinesArr[0]}
mod_perl_response=${sshResponseLinesArr[1]}
Here is how I do remote data collection using ssh
Some remarks
As this function is intended to collect datas, not to connect host (as they don't stay connected), I've renamed them ;-)
Avoid useless forks! use printf -v varname ... instead of varname=$(printf ...)
Moved STDERR redirection 2>/dev/null at more suited place.
use local to reserve variables names into function scope.
printf must have correct number of arguments, corresponding to number of %s see This format string has 3 variable....
Don't use -i switch to grep if not needed!
remote_collect() {
local target_host=$1 host_answer rhelInfo perlInfo
{
read -r host_answer
read -r rhelInfo
read -r perlInfo
} < <(
ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" \
-o StrictHostKeyChecking=no -o PasswordAuthentication=no \
/bin/sh <<-EOF
hostname
awk 'END{print $7}' </etc/redhat-release
rpm -qa | grep mod_perl
EOF
) 2>/dev/null
if [[ $? -eq 0 ]] ;then
printf "| %-10s | %-14s | %-29s |\n" \
"host_answer" "$rhelInfo" "$perlInfo"
else
printf "| %-10s | %-46s |\n" \
"target_host" "Unable to get the ssh connection"
fi
}
Notice: the EOF mark could be preceded by tabulations Tab, but not spaces! I've dropped tabulation before posting to ensure they won't be converted in space during cut'n paste.
And the head line could be
printf -v marker '%61s' ''
marker=${marker// /-}
printf "+%s+\n| %-10s | %-14s | %-29s |\n+%s+\n" \
"$marker" "Hostname" "RedHat Version" "Perl Version" "$marker"
+-------------------------------------------------------------+
| Hostname | RedHat Version | Perl Version |
+-------------------------------------------------------------+
| hostok | 6.3 | mod_perl-2.0.4-10.el6_5.armf |
| hostbad | Unable to get the ssh connection |
Pretty table using UFT-8 borders
printf -v sl %31s '';sl=${sl// /$'\U2500'}
printf '%b%-12s%b%-16s%b%-31s%b\n' \
\\U250c "${sl::12}" \\U252c "${sl::16}" \\U252c "$sl" \\U2510 \
\\U2502 ' Hostname' \\U2502 ' RedHat Version' \\U2502 ' Perl Version' \
\\U2502 \\U251c "${sl::12}" \\U253c "${sl::16}" \\U253c "$sl" \\U2524
then:
if [[ $? -eq 0 ]] ;then
printf "\U2502 %-10s \U2502 %-14s \U2502 %-29s \U2502\n" \
"$host_answer" "$rhelInfo" "$perlInfo"
else
printf "\U2502 %-10s \U2502 %-46s \U2502\n" \
"$target_host" " Unable to get the ssh connection"
fi
and finally
# printf -v sl %31s '';sl=${sl// /$'\U2500'} # uncomment if $sl not at main scope
printf '\U2514%s\U2534%s\U2534%s\U2518\n' "${sl::12}" "${sl::16}" "$sl"
should produce:
┌────────────┬────────────────┬───────────────────────────────┐
│ Hostname │ RedHat Version │ Perl Version │
├────────────┼────────────────┼───────────────────────────────┤
│ hostok │ 6.3 │ mod_perl-2.0.4-10.el6_5.armf │
│ hostbad │ Unable to get the ssh connection │
└────────────┴────────────────┴───────────────────────────────┘
You can run both commands in one ssh run and then parse the results, like this for example:
...
remote_data=($(
ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" -o StrictHostKeyChecking=no -o PasswordAuthentication=no "
rhelInfo=\$(cat /etc/redhat-release | awk 'END{print \$7}')
perlInfo=\$(rpm -qa | grep -i mod_perl)
echo \$rhelInfo \$perlInfo
"))
rhelInfo=${remote_data[0]}
perlInfo=${remote_data[1]}
...
Explanation:
remote_data=( $(ssh ...) ) - will create an array 'remote_data' and fill it with values from output of the command in $() Array will automatically split values by space, tab or new line. So it this case we will have remote_data=( 6.9 mod_perl-2.0.4-11.el6_5.x86_64 )
And then these values are assigned to variables:
rhelInfo=${remote_data[0]}
perlInfo=${remote_data[1]}
BTW echo(and cat)) is an overkill here, so this could be simplified to:
...
remote_data=($(
ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" \
-o StrictHostKeyChecking=no \
-o PasswordAuthentication=no "
awk 'END{print \$7}' /etc/redhat-release
rpm -qa | grep -i mod_perl
"
))
rhelInfo=${remote_data[0]}
perlInfo=${remote_data[1]}
...
I am Keeping it here after testing from my side with #F. Hauri answer..
#!/bin/bash
###########
printf -v sl %32s '';sl=${sl// /$'\U2500'}
printf '%b%-12s%b%-16s%b%-32s%b\n' \
\\U250c "${sl::12}" \\U252c "${sl::16}" \\U252c "$sl" \\U2510 \
\\U2502 ' Hostname' \\U2502 ' RedHat Version' \\U2502 ' Perl Version' \
\\U2502 \\U251c "${sl::12}" \\U253c "${sl::16}" \\U253c "$sl" \\U2524
remote_collect() {
target_host=$1
{
read -r rhelInfo
read -r perlInfo
} < <(
ssh -i /home/zabbix/.ssh/ssh_key "root#${target_host}" \
-o StrictHostKeyChecking=no -o PasswordAuthentication=no \
/bin/sh <<-EOF
cat /etc/redhat-release | awk 'END{print \$7}'
rpm -qa | grep mod_perl
EOF
) 2>/dev/null
if [[ $? -eq 0 ]] ;then
printf "\U2502 %-10s \U2502 %-14s \U2502 %-28s \U2502\n" \
"$target_host" "$rhelInfo" "$perlInfo"
else
printf "\U2502 %-10s \U2502 %-14s \U2502 %-29s \U2502\n" \
"$target_host" "?" "Unable to connect"
fi
# printf -v sl %31s '';sl=${sl// /$'\U2500'} # uncomment if $sl not at main scope
printf '\U2514%s\U2534%s\U2534%s\U2518\n' "${sl::12}" "${sl::16}" "$sl"
} 2>/dev/null
export -f remote_collect
< /home/zabbix/hostsList.txt xargs -P30 -n1 -d'\n' bash -c 'remote_connect "$#"' --
Output 1:
┌────────────┬────────────────┬────────────────────────────────┐
│ Hostname │ RedHat Version │ Perl Version │
├────────────┼────────────────┼────────────────────────────────┤
│ foxnl46 │ ? │ Unable to connect │
└┴┴┘
│ foxnl27 │ 6.7 │ mod_perl-2.0.4-11.el6_5.x86_64 │
└┴┴┘
│ foxnl32 │ 6.7 │ mod_perl-2.0.4-11.el6_5.x86_64 │
If i remove the last printf it all turns okay expect the last line for table.
Output 2
┌────────────┬────────────────┬────────────────────────────────┐
│ Hostname │ RedHat Version │ Perl Version │
├────────────┼────────────────┼────────────────────────────────┤
│ foxnl46 │ ? │ Unable to connect │
│ foxnl27 │ 6.7 │ mod_perl-2.0.4-11.el6_5.x86_64 │
│ foxnl32 │ 6.7 │ mod_perl-2.0.4-11.el6_5.x86_64 │

Adding the Alias name from keytool to my working script [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed last year.
Improve this question
I have the following working script however, I need to get the Alias name: and add this into my script, I have been down many rabbit holes and think I have confused myself and need some guidance.
#!/bin/sh
until=$(keytool -list -v -keystore /usr/java/jdk1.8.0_301-
amd64/jre/lib/security/cacerts -storepass changeit | grep "until:" |
sed 's/^.*until: //')
now_seconds=`date +%s`
now_days=$((now_seconds / 86400))
IFS=$'\n'
for line in $until
do
#if [ echo $line | grep -i alias ]
#then cert_name=${$line}
#else detail =
certdate_secs=$(date +%s --date="$line")
certdate_days=$((certdate_secs / 86400))
expiry_date=$(($certdate_days - $now_days))
if [[ $expiry_date -le 30 ]];
then
echo -e "The Server hostng the cert is $HOSTNAME\n"
echo -e "#############################################\n"
echo -e "This is the keytool cert expiry in seconds:
$certdate_secs\n"
echo -e "This is the keytool cert expiry in days:
$certdate_days\n"
echo -e "#############################################\n" #>
$file
echo -e "The cert will expiry in $expiry_date days\n" #> $file
echo -e "********************************************\n" #> $file
fi
done
You can use GNU awk for preprocessing keytool output:
#!/bin/bash
keystore=/usr/java/jdk1.8.0_301-amd64/jre/lib/security/cacerts
storepass='<PWD>'
keytool -list -v -keystore "$keystore" -storepass "$storepass" |
awk '
BEGIN { now = systime() }
/^Alias name:/ { alias = $3 }
! /^Valid from:/ { next }
{ sub(/.*: /,"") }
{ $2 = (index("JanFebMarAprMayJunJulAugSepOctNovDec",$2) + 2) / 3 }
{ print alias,int((mktime($6" "$2" "$3" "gensub(/:/," ","g",$4)" "$5)-now)/86400) }
' |
while read -r cert_alias expiry_days
do
if (( expiry_days < 30 ))
then
echo "$cert_alias will expire in $expiry_days days"
fi
done

Execute bash script via ansible playbook

I'm looking to run the following shell script via ansible playbook.
#!/bin/bash
oci compute instance list --lifecycle-state RUNNING --region ca-toronto-1 --compartment-id < compartment OCID> --all | grep display-name -A 0 > hostnames.txt
for line in `cat hostnames.txt`
do
#echo $line
if [[ $line == *","* ]]; then
# hostname=$(echo ${line//"display-name"/} | tr -d '",: ')
hostname=$(echo "$line" | tr -d '",')
echo "$hostname"
ssh -tt "$hostname" "sudo puppet agent -tv && sleep 10"
# break
fi
done
This works just like how i want when i run the shell script but I get a blank output when i run via ansible.
Playbook:
---
- name: puppet agent trigger
gather_facts: false
become_user: true
hosts: all
tasks:
- name: trigger puppet agent
shell: |
oci compute instance list --lifecycle-state RUNNING --region ca-toronto-1 --compartment-id <compartment OCID> --all | grep display-name -A 0 > hostnames.txt
for line in `cat hostnames.txt`
do
if [[ $line == *","* ]]; then
hostname=$(echo "$line" | tr -d '",')
echo "$hostname"
ssh -tt "$hostname" "sudo puppet agent -tv && sleep 10"
fi
done
register: shell_output
- debug:
msg: "{{ shell_output.stdout }}"
Please point me as to what im missing.
According the description of your use case it seems to be recommended to transfer the whole logic of the script into Ansible itself. To do so and in respect to the comment regarding add_host_module, you could use an approach like
- name: Create an instance list
shell:
cmd: oc get nodes --no-headers | cut -d " " -f 1 | tr '\n' "," | rev | cut -c 2- | rev
register: instance_list
changed_when: false
To generate the instance_list I've used an OpenShift cluster as example, because I don't have something like oci compute instance list ... accessible.
- name: Add all hosts from instance_list to the script group
add_host:
name: '{{ item }}'
groups: script
loop: "{{ instance_list }}"
From there you could proceed further to execute your command puppet agent -tv && sleep 10.

How to pass value to ansible command module

I am new to ansible and trying to write some basic playbook. I need to run a command via command module, but that command needs use a value derived from other command this is what I have:
+++++++++++++++++++++++++++++++++++++++++++
---
- name: Post SentinelOne Agent
hosts: all
tasks:
- name: user sentinel exist
command: /usr/bin/grep sentinelone /etc/passwd
register: user_exist
ignore_errors: yes
- name: Create sentinelone user using existing id, only if the user does not exist
command: "useradd -d /opt/sentinelone/home/ -u `ls -ld /opt/sentinelone/ | awk '{print $3}'`** -f 1 -l -g sentinelone -s /sbin/nologin sentinelone"
when: user_exist.rc == 1
- name: Check again to confirm user exist for copy purpose
command: /usr/bin/grep sentinelone /etc/passwd
register: does_user_exist
ignore_errors: yes
- name: Whitelist sentinelone user ... Copy line from /etc/passwd
command: echo "`cat /etc/passwd | grep -i sentinelone`" >> /etc/crypt/passwd_local
when: does_user_exist.rc == 0
- name: Whitelist sentinelone user ... Copy line from /etc/shadow
command: echo "`cat /etc/shadow | grep -i sentinelone`" >> /etc/crypt/shadow_local
when: does_user_exist.rc == 0
+++++++++++++++++++++++++++++
get error:
for
command: "useradd -d /opt/sentinelone/home/ -u `ls -ld /opt/sentinelone/ | awk '{print $3}'`** -f 1 -l -g sentinelone -s /sbin/nologin sentinelone"
STDERR:
useradd: invalid user ID '`ls'
MSG:
non-zero return code

Ansible: escape quotes and listing users password expiry information

How to escape in shell module quotation?
I've tried as follows:
- name: UList
shell: "cut -f 1 -d: /etc/passwd | sudo xargs -n 1 -I {} bash -c \" echo {} ; chage -l {}\""
and
- name: UList
shell: "cut -f 1 -d: /etc/passwd | sudo xargs -n 1 -I {} bash -c \' echo {} ; chage -l {}\'"
Where is a mistake?
This playbook worked for me, hope this will be helpful for you too. You can use single quotes' for a command if you have an issue escaping " quote
Either do it this way
'cut -f 1 -d: /etc/passwd | sudo xargs -n 1 -I {} bash -c " echo {} ; chage -l {}"'
Or
"cut -f 1 -d: /etc/passwd | sudo xargs -n 1 -I {} bash -c ' echo {} ; chage -l {}'"
Both are working i have tested it.
---
- name: Set my hosts variable
hosts: localhost
tasks:
- name: UList
shell: 'cut -f 1 -d: /etc/passwd | sudo xargs -n 1 -I {} bash -c " echo {} ; chage -l {}"'
register: result
- name: debug
debug:
msg: "{{result}}"
Or
For the output you are expecting for that you can use
awk -F':' '{ system("echo " $1 " && chage -l " $1) }' /etc/passwd
Command explanation
---
- name: Set my hosts variable
hosts: localhost
tasks:
- name: UList
shell: "awk -F':' '{ system(\"echo \" $1 \" && chage -l \" $1) }' /etc/passwd"
register: result
- name: debug
debug:
msg: "{{result}}"

Resources