running a for loop over ssh remotely - bash

team, I have below cord that does ssh login and stays connected. I want to run some commands in for loop but getting some syntax errors. The same exact commands work when i manually login to node and sudo bash and just copy paste.
code
read -p "specify just the list of nodes " nodes
for node in $nodes
do
ssh -q -F $HOME/.ssh/ssh_config -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $node.team.net \
"for line in `docker ps | grep test | awk '{print $1}'`;
do
POD_ID=$(docker inspect $line --format='{{ index .Config.Labels "io.kubernetes.pod.uid" }}')
POD_NAME=$(docker inspect $line --format='{{ index .Config.Labels "io.kubernetes.pod.name"}}')
POD_VOL="/var/lib/kubelet/pods/$POD_ID/volumes"
POD_DU=$(du -sh $POD_VOL < /dev/null)
HOSTNAME=$(hostname)
AGENT_SHA=$(docker inspect $line --format='{{ index .Config.Image }}' | cut -d ':' -f2)
STARTED_AT=$(docker inspect $line --format='{{ .State.StartedAt }}')
echo $HOSTNAME, $POD_NAME, $POD_DU, $AGENT_SHA, $STARTED_AT
done"
printf "\n"
done;
output
Your new SSH certificate is ready for use!
specify just the list of nodes node1
"docker inspect" requires at least 1 argument.
See 'docker inspect --help'.
Usage: docker inspect [OPTIONS] NAME|ID [NAME|ID...]
Return low-level information on Docker objects
"docker inspect" requires at least 1 argument.
See 'docker inspect --help'.
expected
container1 45GB
..
..

Is better send a file with script content and run. Something like:
Copy script
for a in {server1,server2,serverN};
do
scp your_script.sh root#$a:/path/to/your_script.sh
done
Exec script
for a in {server1,server2,serverN};
do
ssh root#$a "sh /path/to/your_script.sh par1 par2 parn";
done

Related

how to terminate a process via key stroke

I have this function on my bash script:
sudo tshark -i eth0 -T fields -e ip.src -e dns.qry.name -Y "dns.qry.name~." -q 1>>log.txt 2>/dev/null &
while true
do
cat log.txt
done
it is capturing ips and domain names in live mode and save them into log file.
how can configure this live mode to be terminated by pressing a key?
Using tee to watch log and send the command to background, then read input to terminate script
tshark -i eth0 -T fields -e ip.src -e dns.qry.name -Y "ip" -q 2>/dev/null | tee log.txt &
read -n1 c && echo "Got key $c"
exit
Note: running the command in a console will terminate it :-p

Nested quoting in bash

I'm connecting to a remote server via SSH:
ssh -i ~/.ssh/pk.pem user#server
and then, on that server, open bash within a Docker container:
docker exec -it $(docker ps | grep ecs-worker-low | cut -d ' ' -f1) bash
This works fine. (Note that I need to get the container ID like this. I'm not able to name the container.)
I would like to combine the two commands, so that I only run one command and get the shell within the container. This can be done with something like this:
ssh -i ~/.ssh/pk.pem user#server -t "bash -c 'docker exec -it $(docker ps | grep ecs-worker-low | cut -d ' ' -f1) bash'"
However this doesn't work because of the nested single quotes. I haven't found any way around this. Can you please help me? Thank you.
You can avoid the use of cut with --filter and --format
ssh -t -i ~/.ssh/pk.pem user#serve 'docker exec -it $(docker ps --filter ancestor=ecs-worker-low --format {{.ID}}) bash'
It's probably easiest to use a heredoc:
ssh -i ~/.ssh/pk.pem user#server -t << \EOF
docker exec -it $(docker ps | grep ecs-worker-low | cut -d ' ' -f1)
EOF
Make sure you use a non-interpolating heredoc. If you omit the backslash on the initial delimiter, the process substitution will be made on the local host.
Swap the quotes:
ssh -i ~/.ssh/pk.pem user#server -t 'bash -c "docker exec -it $(docker ps | grep ecs-worker-low | cut -d " " -f1) bash"'
All the double quotes are literal characters as far as ssh is concerned, and the command substitution creates a new context so that the first inner quote does not close the first outer quote. That said...
... Simplifying matters, you likely don't need the outer bash; ssh can run docker for you directly:
ssh -i ~/.ssh/pk.pem user#server -t 'docker exec -it $(docker ps | grep ecs-worker-low | cut -d " " -f1) bash'

Bash Script fails with error: OCI runtime exec failed

I am running the below script and getting error.
#!/bin/bash
webproxy=$(sudo docker ps -a --format "{{.Names}}"|grep webproxy)
webproxycheck="curl -k -s https://localhost:\${nginx_https_port}/HealthCheckService"
if [ -n "$webproxy" ] ; then
sudo docker exec $webproxy sh -c "$webproxycheck"
fi
Here is my docker ps -a output
$sudo docker ps -a --format "{{.Names}}"|grep webproxy
webproxy-dev-01
webproxy-dev2-01
when i run the command individually it works. For Example:
$sudo docker exec webproxy-dev-01 sh -c 'curl -k -s https://localhost:${nginx_https_port}/HealthCheckService'
HEALTHCHECK_OK
$sudo docker exec webproxy-dev2-01 sh -c 'curl -k -s https://localhost:${nginx_https_port}/HealthCheckService'
HEALTHCHECK_OK
Here is the error i get.
$ sh healthcheck.sh
OCI runtime exec failed: exec failed: container_linux.go:348: starting container process caused "exec: \"webproxy-dev-01\": executable file not found in $PATH": unknown
Could someone please help me with the error. Any help will be greatly appreciated.
Because the variable contains two tokens (on two separate lines) that's what the variable expands to. You are running
sudo docker exec webproxy-dev-01 webproxy-dev2-01 ...
which of course is an error.
It's not clear what you actually expect to happen, but if you want to loop over those values, that's
for host in $webproxy; do
sudo docker exec "$host" sh -c "$webproxycheck"
done
which will conveniently loop zero times if the variable is empty.
If you just want one value, maybe add head -n 1 to the pipe, or pass a more specific regular expression to grep so it only matches one container. (If you have control over these containers, probably run them with --name so you can unambiguously identify them.)
Based on your given script, you are trying to "exec" the following
sudo docker exec webproxy-dev2-01
webproxy-dev-01 sh -c "curl -k -s https://localhost:${nginx_https_port}/HealthCheckService"
As you see, here is your error.
sudo docker exec webproxy-dev2-01
webproxy-dev-01 [...]
The problem is this line:
webproxy=$(sudo docker ps -a --format "{{.Names}}"|grep webproxy)
which results in the following (you also posted this):
webproxy-dev2-01
webproxy-dev-01
Now, the issue is, that your docker exec command now takes both images names (coming from the variable assignment $webproxy), interpreting the second entry (which is webproxy-dev-01 and sepetrated by \n) as the exec command. This is now intperreted as the given command which is not valid and cannot been found: That's what the error tells you.
A workaround would be the following:
webproxy=$(sudo docker ps -a --format "{{.Names}}"| grep webproxy | head -n 1)
It only graps the first entry of your output. You can of course adapt this to do this in a loop.
A small snippet:
#!/bin/bash
webproxy=$(sudo docker ps -a --format "{{.Names}}"| grep webproxy )
echo ${webproxy}
webproxycheck="curl -k -s https://localhost:\${nginx_https_port}/HealthCheckService"
while IFS= read -r line; do
if [ -n "$line" ] ; then
echo "sudo docker exec ${line} sh -c \"${webproxycheck}\""
fi
done <<< "$webproxy"

Looping over arguments in bash array for docker commands?

I seem to be stuck here. I'm attempting to write a bash function that starts x number of docker containers, wish an array that holds exposed ports for the given app. I don't want to loop over the array, just the commands, while referencing the array to get the value. The function looks like this:
#!/bin/bash
declare -a HOSTS=( ["app1"]="8002"
["app2"]="8003"
["app3"]="8008"
["app4"]="8009"
["app5"]="8004"
["app6"]="8007"
["app7"]="8006" )
start() {
for app in "$#"; do
if [ "docker ps|grep $app" == "$app" ]; then
docker stop "$app"
fi
docker run -it --rm -d --network example_example \
--workdir=/home/docker/app/src/projects/"$app" \
--volume "${PWD}"/example:/home/docker/app/src/example \
--volume "${PWD}"/projects:/home/docker/app/src/projects \
--volume "${PWD}"/docker_etc/example:/etc/example \
--volume "${PWD}"/static:/home/docker/app/src/static \
--name "$app" --hostname "$app" \
--publish "${HOSTS["$app"]}":"${HOSTS["$app"]}" \
example ./manage.py runserver 0.0.0.0:"${HOSTS[$app]}";
echo "$app"
done
}
And I want to pass arguments like so:
./script.sh start app1 app2 app4
Right now it isn't echoing the app so that points towards the for loop being declared incorrectly...could use some pointers on this.
This line:
if [ "docker ps|grep $app" == "$app" ];
doesn't do what you want. It looks like you mean to say:
if [ "$(docker ps | grep "$app")" == "$app" ];
but you could fail to detect two copies of the application running, and you aren't looking for the application as a word (so if you look for rm you might find perform running and think rm was running).
You should consider, therefore, using:
if docker ps | grep -w -q "$app"
then …
fi
This runs the docker command and pipes the result to grep, and reports on the exit status of grep. The -w looks for a word containing the value of "$app", but does so quietly (-q), so grep only reports success (exit status 0) if it found at least one matching line or failure (non-zero exit status) otherwise.
docker ps -f lets you conveniently check programmatically whether a particular image is running.
for app in "$#"; do
if docker ps -q -f name="$app" | grep -q .; then
docker stop "$app"
:
Unfortunately, docker ps does not set its exit code (at least not in the versions I have available -- I think it has been fixed in some development version after 17.06 but I'm not sure) so we have to use an ugly pipe to grep -q . to check whether the command produced any output. The -q flag just minimizes the amount of stuff it prints (it will print just the container ID instead of a bunch of headers and columnar output for each matching container).

Shell script to cleanup specified docker containers using grep

I want to write a script that is executed by my development build server that will remove any 'similar' docker containers before building and running a new container.
Below is pseudo code for the bash script I need
var name = $1
var number_of_results = # of containers returned from $(docker ps -a | grep "$name")
if(number_of_result > 0)
docker rm -f $(docker ps -a | grep "$name")
You can just use this script in shell:
name="${1?one argument needed}"
ids=$(docker ps -a | awk -v name="$name" '$NF ~ name{print $1}')
[[ -n $ids ]] && docker rm -f $ids

Resources