Bash execute multiple command to a remote server on EOF - bash

I try from my terminal, to execute on remote server a openstack command to a docker. The purpose is to get the id of openstack project.
when condition is true, I want to get id, but the script below failed to get id. I don't know if I can execute if condition to EOF statement
ret="$(ssh -qT root#server << EOF
docker exec openstack bash -c ". adminrc &&
if [ false ]; then openstack project create p_ops &>/dev/null
else :
fi
id_u=$(openstack user show u_ops | grep " id" | cut -d "|" -f3 | xargs)
openstack role add SwiftOperator --project p_ops --user $id_u
id_p=$(openstack project show p_ops | grep " id" | cut -d "|" -f3|xargs)
echo "$id_p""
EOF
)"
I get the output :
Missing value auth-url required for auth plugin password
Missing value auth-url required for auth plugin password
usage: openstack role add [-h]
[--system <system> | --domain <domain> | --project <project>]
[--user <user> | --group <group>]
[--group-domain <group-domain>]
[--project-domain <project-domain>]
[--user-domain <user-domain>] [--inherited]
[--role-domain <role-domain>]
<role>
openstack role add: error: argument --user: expected one argument
I desired the id of project :
echo $id_p
faafe2044c4235ac648faaceae5d1a3bf2a8f7a8ca8a765f5a9621a5e53d9162

You can avoid the use of nested quotes which are giving you problems.
Instead of the complex sentence:
openstack user show u_ops | grep " id" | cut -d "|" -f3 | xargs
you can just write:
openstack user show -f value -c id
ret=$(ssh -qT root#server << EOF
docker exec openstack bash -c ". adminrc &&
if [ false ]; then openstack project create p_ops &>/dev/null
else :
fi
id_u=$(openstack user show -f value -c id u_ops)
openstack role add SwiftOperator --project p_ops --user $id_u
id_p=$(openstack project show -f value -c id p_ops)
echo $id_p"
EOF
)

Related

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.

Multiple conditions in a shell script for loop

I'm trying to loop through 2 groups on macOS and remove users in the admin group if they don't exist in another group.
newadmins=$(dscl . -read Groups/newadmin GroupMembership | cut -c 18-)
adminUsers=$(dscl . -read Groups/admin GroupMembership | cut -c 18-)
for (user in $adminUsers && ! user in $newadmins)
do
dseditgroup -o edit -d $user -t user admin
if [ $? = 0 ]; then echo "Removed user $user from admin group"; fi
else
echo "Admin user $user left alone"
fi
done
The above didn't work. I think I'm confusing shell with other languages.
Any help would be appreciated. Thank!
The below script worked exactly as expected:
NEW_ADMIN_USERS=$(dscl . -read Groups/newadmin GroupMembership | cut -d ' ' -f 2-)
ADMIN_USERS=$(dscl . -read Groups/admin GroupMembership | cut -d ' ' -f 2-)
DEFUNCT_ADMIN_USERS=$(grep -vxFf <(echo ${NEW_ADMIN_USERS} | tr ' ' '\n') <(echo ${ADMIN_USERS} | tr ' ' '\n'))
for DEFUNCT_ADMIN_USER in ${DEFUNCT_ADMIN_USERS}
do
if dseditgroup -o edit -d ${defunct_admin_user} -t user admin
then
echo "Removed user ${DEFUNCT_ADMIN_USER} from admin group"
else
echo "Admin user ${DEFUNCT_ADMIN_USER} left alone"
fi
done
Thanks #msbit for all the help!
I would consider doing something like this:
#!/usr/bin/env bash
set -eu
NEW_ADMIN_USERS=$(dscl . -read Groups/newadmin GroupMembership | cut -d ' ' -f 2-)
ADMIN_USERS=$(dscl . -read Groups/admin GroupMembership | cut -d ' ' -f 2-)
DEFUNCT_ADMIN_USERS=$(grep -vxFf <(echo ${NEW_ADMIN_USERS} | tr ' ' '\n') <(echo ${ADMIN_USERS} | tr ' ' '\n'))
for DEFUNCT_ADMIN_USER in ${DEFUNCT_ADMIN_USERS}
do
if dseditgroup -o edit -d ${DEFUNCT_ADMIN_USER} -t user admin
then
echo "Removed user ${DEFUNCT_ADMIN_USER} from admin group"
else
echo "Admin user ${DEFUNCT_ADMIN_USER} left alone"
fi
done
The main thrust of this is using the grep command put forward by #Jetchisel with process substitution (<()) to prepare a list of admin users in the ADMIN_USERS variable but not in the NEW_ADMIN_USERS variable, then iterating over that variable.
This departs from your approach in a number of ways:
setting the errexit and nounset options which will cause the script to exit on any error code from a command, including use of unset variables (set -eu)
using the field argument of cut with delimiter set to space when parsing the output of dscl (cut -d ' ' -f 2-)
subsequently splitting the list of users into lines with tr (tr ' ' '\n')
passing the list through to for as appropriate (using ( was a syntax error, as I suspect the use of ! would be)
evaluating the return code of dseditgroup directly as that is what if is testing for
removing the trailing fi for the first if command, as it's not needed when you have the else (and would cause a syntax error due to an apparent floating else)
Please test thoroughly, preferably with a dummy command instead of dseditgroup before you're 100% happy that this works as expected, and consider setting the xtrace option (set -x which will echo all the commands as they are executed), while developing.

command execute with error when use expect in shell script while work fine in pure shell

I try to start all the exited docker containers deployed in separated servers, so basically i should execute the essential command below
[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)
It worked fine like in pure linux shell , but then error occured(show below) when i try to use expect to "send" the "essential" command. (local ip is 241,remote end is 209)
[root#localhost start_shell_dir]# spawn ssh root#192.168.1.209
root#192.168.1.209's password:
Last login: Fri Oct 15 22:23:25 2021 from 192.168.1.241
[root#localhost ~]# invalid command name "0"
while executing
"0 -ne 0 "
invoked from within
"send "[ 0 -ne 0 ] && docker start ""
The error log shows i have already log in the remote machine, and something wrong when i execute the docker command.
Glenn jackman from the comment area shows me the basic rule for tcl,then i realize expect does command substitutions before sending real command. We may see it from execute bash -x script.sh .
[root#localhost start_shell_dir]# bash -x startContainer.sh
+ read ip pass
+ read ip pass
+ /usr/bin/expect
[root#localhost start_shell_dir]# ++ docker ps -a
++ grep Exited
++ wc -l
++ docker ps -a
++ grep Exited
++ cut '-d ' -f1
spawn ssh root#192.168.1.209
root#192.168.1.209's password:
Last login: Fri Oct 15 22:37:56 2021 from 192.168.1.241
[root#localhost ~]# invalid command name "0"
while executing
"0 -ne 0 "
invoked from within
"send "[ 0 -ne 0 ] && docker start ""
Anyway, the final command that work for me is the command showed below(replace double quotes with braces and with backslash before $() to keep it as an ordinary character rather than pre-parse it).
send {[ \$(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start \$(docker ps -a | grep Exited | cut -d' ' -f1)}
#!/bin/bash
# my original script with error
while read ip pass
do
{
/usr/bin/expect <<-END
spawn ssh root#$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect "#"
send "[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)"
expect eof
END
}&
done<apps_ip.txt
Like the shell, Tcl (and expect) allows interpolation with double quotes. Tcl uses square brackets for command substitution (in the same way that the shell uses $(...))
Use curly braces to protect the contents of that string (analogous to the shell's single quotes):
send {[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)}
#....^.............................................................................................................^
# and don't forget to hit Enter
send "\r"
See https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm for the few syntax rules of Tcl.

ssh when invoked with variables form while loop not working

I am running into an issue where I am comparing two files (alert.txt and env.txt) and based on common value, I am pulling complete line data from env.txt based on matching entry. I am reading these values into while loop and then invoking a function as follows. the ssh call is not working and also the while loop inside start_admin not working
#!/bin/bash
start_admin()
{
ssh -n -f $user#$host "sh -c 'cd $domain; ./script.sh > /dev/null 2>&1'"
while !(netstat -na | grep -E $host:$port|grep -E LISTEN) 2>/dev/null
sleep 30
do
echo "waiting"
done
echo "started"
}
grep -Ff alert.txt env.txt | (while IFS=" " read -r r1 r2 r3 r4 r5
do
user=$r2
host=$r3
domain=$r4
port=$r5
done
start_admin $user $host $domain $port
)
and contents of alert.txt is:
env2
env3
and that of env.txt is :
env1 user1 host1 /app/domain1/ port1
env2 user2 host2 /app/domain2/ port2
env3 user3 host3 /app/domain3/ port3
I could solve this with multiple if else loops, but that is not a desired solution, please guide me in right direction as to what is missing ?
Use join instead of grep here to avoid false positives
Because your while read loop completes before you run start_admin, you only launch it once (done should be AFTER start_admin)
In start_admin, don't use $user, $host and so on, use $1, $2 (or use them but don't pass them as parameters when calling the function)
I'm not sure exactly what you try to achieve, but here is a revised version already.
#!/bin/bash
start_admin()
{
sanitized_domain=${domain//'"'/'\"'}
ssh -n -f "$user#$host" "sh -c 'cd \"$sanitized_domain\"; ./script.sh >/dev/null 2>&1'"
while ! netstat -na | grep -q " $host:$port .*LISTEN"; do
echo waiting
sleep 30
done
echo started
}
join alert.txt env.txt | while IFS=' ' read -r env user host domain port; do
start_admin
done
)

How do I say the shell script to run within a given time-frame?

I am using the following shell script to fetch data from the database,and
in these fetched data I have a field named 'frequency', then I need to
set the script to run according to this frequency.Can I handle this
functionality in the script so that it will tell the crone job to run it
frequently?
#! /bin/bash
######## Settings ########
BASE_DIR_PATH='/var/www/html/aer/'
######## End Settings ########
CUS_PHP_FILE_PATH='shd/save_customer_info.php'
EMAIL_PHP_FILE_PATH='shd/email_customer_report.php'
CUSTOMER_REPORT_STORAGE_DIRECTORY='ev/customer_report/'
COMPLETED_CUSTOMER_REPORT_STORAGE_DIRECTORY='ev/rty'
LOG_DIRECTORY='ev/customer_report/logs'
DB_PHP_FILE='db/db_config.php'
#Obtain FTP server credentials from database
DB_FILE_NAME="$BASE_DIR_PATH$DB_PHP_FILE"
DB_NAME=`cat $DB_FILE_NAME | grep DB_DATABASE | cut -d \' -f 4`
DB_USERNAME=`cat $DB_FILE_NAME | grep DB_SERVER_USERNAME | cut -d \' -f
4`
DB_PASSWORD=`cat $DB_FILE_NAME | grep DB_SERVER_PASSWORD | cut -d \' -f
4`
FTP_PROFILE='bgty'
SYSTEM_PACKAGE='bfgtt'
results=($(mysql --user $DB_USERNAME -p${DB_PASSWORD} ${DB_NAME} -Bse
"SELECT api_url,api_user_name,api_password,frequency FROM
brt_profile WHERE profile_name='$FTP_PROFILE' AND
distributor='$SYSTEM_PACKAGE'"))
if [ $? -ne 0 ]; #check if database connection is failed
then
exit
fi

Resources