Unable to execute the If condition in shell script - linux

I need to check if container is already present with specific name.
Using if statement for same, however container is present with same name but i am not sure why if statement is not running successfully.
if [`echo password | sudo -S docker ps -all|grep test|cut -d' ' -f1`]
then
statements
else
statements
container with test name is present but its always going inside the else statement. Could you help me on this.

You need blanks between [, ] and `, i.e. :
if [ `echo password | sudo -S docker ps -all|grep test|cut -d' ' -f1` ]
Also, you need fi after the last line.

in addition to #ÔHARA Kazutaka information.
-all does not exists, try --all instead.
The --quiet --filter name=test options are going to make docker filters output using the container's name, and make it prints to the standard output the CONTAINER ID if a container exists.
Give a try to this:
container_name=test
container_id=$(echo password | sudo -S docker ps --all --quiet --filter name="${container_name}")
if [ ! -z "${container_id}" ] ; then
printf "%s is the id of the container with name '%s'\n" "${container_id}" "${container_name}"
else
printf "no docker container with name '%s' has been found.\n" "${container_name}"
fi

Related

How to find all image tags of a running Docker container?

I have a bunch of Docker containers running on a server and I used the "latest" tag or no tag at all for all of them. Now I want to freeze the image versions, but I have no idea when I pulled these images, so I can't tell which version "latest" is referring to. docker ps is just showing me that the containers use the "latest" or no tag, like this:
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
371d6675888b node:latest "npm start" 6 days ago Up 2 hours project_xyz_1
ca5a75425a34 selenium/node-chrome "/usr/bin/nohup go..." 6 days ago Up 2 hours project_xyz-chrome_1
...
All images that I use are public images from the docker hub.
I thought maybe I could use the hex ID that docker ps shows for all the containers, but then I realized that the IDs are container IDs and not image IDs.
Is it maybe possible to get the image IDs/hashes of all running containers and then scan for all matching tags or something like that?
Docker version: 18.09.1, build 4c52b90
Edit:
So there have been some answers showing how to get the IDs (digests) of the images, but I need to somehow find the actual tags of those images.
After doing some research, I found that the docker hub has an API and that there is a way to get all tags for a given image and there is a way to get the digest for a given image+tag. After looking at the API and a lot of examples from stackoverflow, I came up with this:
(It also includes the code required to get the digest of local images, taken form the answers below)
function getDigestByImageNameWithTag () {
TARGET_IMAGE_NAME_WITH_TAG="$1" # works with and without tag
docker image inspect --format '{{index .RepoDigests 0}}' "$TARGET_IMAGE_NAME_WITH_TAG" | cut -d '#' -f2
}
function getTagsByDigest () {
TARGET_IMAGE_NAME="$1"
TARGET_DIGEST="$2"
# prepend the image name with "library/" if it doesn't contain a slash
if [[ $TARGET_IMAGE_NAME != *"/"* ]]; then
TARGET_IMAGE_NAME="library/$TARGET_IMAGE_NAME"
fi
# get authorization token for the given image name
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$TARGET_IMAGE_NAME:pull" | jq -r .token)
# find all tags for the given image name
ALL_TAGS=$(curl -s -H "Authorization: Bearer $TOKEN" https://index.docker.io/v2/$TARGET_IMAGE_NAME/tags/list | jq -r .tags[])
# itate over all these tags
for TAG in ${ALL_TAGS[#]}; do
# get image digest
DIGEST=$(curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/$TARGET_IMAGE_NAME/manifests/$TAG | grep Docker-Content-Digest | cut -d ' ' -f 2)
# if the tag matches the given digest
if [[ $TARGET_DIGEST = $DIGEST ]]; then
# "return" the tag
echo "$TAG"
fi
done
}
function getContainerImageNames () {
docker inspect $(docker ps | awk '{print $2}' | grep -v ID) | jq .[].RepoTags | grep -v "\[" | grep -v "\]" | grep " " | cut -d '"' -f2 | cut -d '/' -f2-
}
# get all image names of all local containers
IMGS_WITH_TAG=$(getContainerImageNames)
# iterate of those image names
for IMAGE_NAME_WITH_TAG in ${IMGS_WITH_TAG[#]}; do
# get the digest of the current iteration's IMAGE_NAME_WITH_TAG
DIGEST=$(getDigestByImageNameWithTag $IMAGE_NAME_WITH_TAG)
echo "TARGET_DIGEST: $DIGEST"
# get the raw image name without the tag
IMAGE_NAME=$(echo "$IMAGE_NAME_WITH_TAG" | cut -d ':' -f1)
# find all tags for this image that have the same digest
MATCHING_TAGS=$(getTagsByDigest $IMAGE_NAME $DIGEST)
echo "Image: $IMAGE_NAME_WITH_TAG"
echo "Image digest: $IMAGE_NAME"
echo "Image tags with same digest: "
echo "$MATCHING_TAGS"
echo "-----------------------------"
done
Unfortunately it seems to take forever to finish. I'm not sure if I'm doing something wrong, but that's the best thing I could come up with.
Any ideas on how to make this work properly?
I think this is a better approach without inspecting the container, as docker ps already printing the docker image tag form which the container is created.
docker inspect $(docker ps | awk '{print $2}' | grep -v ID) | jq .[].RepoTags
So first this gets the list of running containers, then inspect each image being used by running container and using jq get all repo tags of that image.
Here is the output.
Updated:
Here is you go using skopeo , you can do using API but will do the effort, so why if you have skopeo
You do not need to install skopeo you can run the container and then or remove once get the result, or you can install, script support both
running_container=$(docker ps | awk '{print $2}' | grep -v ID)
echo "running container: $running_container"
for image in $running_container
do
local_tag=$(echo "$image" | awk -F":" '{print $2}')
if [ -z $local_tag ]; then
# if tag is empty then tag is latest
local_tag="latest"
image="$image":"$local_tag"
fi
local_digest=$(docker inspect $image | jq '.[].RepoDigests[]' | awk -F"#" '{print $2}' | tr -d '"')
echo "Local digest is:" $local_digest
remote_digest=$(docker run --rm --env image=$image alexeiled/skopeo:latest ash -c "skopeo inspect docker://docker.io/$image" | jq '.Digest' | tr -d '"' )
echo $remote_digest
# option2 install the skopeo on your local system
# remote_digest=$(skopeo inspect docker://docker.io/$image | jq '.Digest' | tr -d '"')
echo "Remote digest is : "$remote_digest
if [ "${local_digest}" == "${remote_digest}" ]; then
echo "local image is up to date with remote"
else
echo "Remote image is updated; please run docker pull $image"
fi
done
The RepoDigest field in the image inspect will have a sha256 reference if you pulled the image from a registry:
docker ps --format '{{.Image}}' | xargs \
docker image inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{end}}'
For a single image like node:latest on your host, that looks like:
docker image inspect --format '{{index .RepoDigests 0}}' node:latest
That digest cannot be changed by a push to the registry of the same tag name. When you pull the updated tag from the registry, you will see this digest update.
The docker inspect command can be used for this.
You can take a look at the answer here https://stackoverflow.com/a/54075889/8113039
Docker images and containers are identified by an ID and for a running container you can get the Id of its image and then pull the image corresponding to the given ID.
First you need to use docker inspect on all your running containers in order to get the sha256 Id the image on which the container is based.
docker inspect returns the image ID under "Image" :
{
"Id": "6de053a2afa4499471c5e5c2afe0b0d83c9c7e50fc7e687fb63a7ebfd2bff320",
...
},
"Image": "sha256:26eb6780e26887a6838684a549562c0404fd85c55f71e0af6c79a4da5505d2a7",
....
}
Then you simply have to pull those images by digest (immutable identifier)
$ docker pull node#sha256:the-image-digest-here
or
$ docker pull node#sha256:26eb6780e26887a6838684a549562c0404fd85c55f71e0af6c79a4da5505d2a7
If you are lucky images corresponding to those digests are still available into the docker hub.
After that, is you are still facing latest images I will suggest you to rename those images with a proper name and tag and pull them in your own docker hub repository to be able to use them directly...

How to get current foldername and remove characters from the name in bash

I'm trying to write a single command in my makefile to get the current folder and remove all "." from the name.
I can get the current folder with $${PWD##*/} and I can remove the "."s with $${PWD//.} but I can't figure out how to combine these two into one.
The reason I need this is to kill my docker containers based on name of project. This is my command:
docker ps -q --filter name="mycontainer" | xargs -r docker stop
and i was hoping I could inject the project name before my container name like this:
docker ps -q --filter name=$${PWD##*/}"_mycontainer" | xargs -r docker stop
You can try:
var=$(echo ${PWD##*/} | sed "s/\.//")
or:
var=$(tmp=${PWD##*/} && printf "${tmp//./}")
In your use case will be something like:
docker ps -q --filter name=$(tmp=${PWD##*/} && printf "%s_mycontainer" "${tmp//./}") | xargs -r docker stop
Note that there are more ways to do that (even more efficient).

Shell script: execute 2 commands and keep first running

I'm trying to write a shell script for my docker image where:
a mssqql server is started
database setup happens
However with my current script my sql server instance stops as soon as the data import is done. Could anyone point me out what I'm doing wrong?
#!/bin/bash
database=myDB
wait_time=30s
password=myPw
exec /opt/mssql/bin/sqlservr &
echo importing data will start in $wait_time...
sleep $wait_time
echo importing data...
/opt/mssql-tools/bin/sqlcmd -S 0.0.0.0 -U sa -P $password -i ./init.sql
for entry in "table/*.sql"
do
echo executing $entry
/opt/mssql-tools/bin/sqlcmd -S 0.0.0.0 -U sa -P $password -i $entry
done
for entry in "data/*.csv"
do
shortname=$(echo $entry | cut -f 1 -d '.' | cut -f 2 -d '/')
tableName=$database.dbo.$shortname
echo importing $tableName from $entry
/opt/mssql-tools/bin/bcp $tableName in $entry -c -t',' -F 2 -S 0.0.0.0 -U sa -P $password
done
I did not see any clear mistakes in your shell script. I am just advising you the below:-
Try to run the server from the current shell of the script without exec
/opt/mssql/bin/sqlservr &
Put some echo in both the loop statements to check what is going on there.
Hope this will help.
Seems I need to add set -m to resolve this.

CoreOS - get docker container name by PID?

I have a list of PID's and I need to get their docker container name. Going the other direction is easy ... get PID of docker container by image name:
$ docker inspect --format '{{.State.Pid}}' {SOME DOCKER NAME}
Any idea how to get the name by PID?
Something like this?
$ docker ps -q | xargs docker inspect --format '{{.State.Pid}}, {{.ID}}' | grep "^${PID},"
[EDIT]
Disclaimer This is for "normal" linux. I don't know anything useful about CoreOS, so this may or may not work there.
Because #Mitar's comment suggestion deserves to be a full answer:
To get container ID you can use:
cat /proc/<process-pid>/cgroup
Then to convert the container ID to docker container name:
docker inspect --format '{{.Name}}' "${containerId}" | sed 's/^\///'
... as a one-liner as well
PID=20168; sudo docker ps --no-trunc | grep $(cat /proc/$PID/cgroup | grep -oE '[0-9a-f]{64}' | head -1) | sed 's/^.* //'
I use the following script to get the container name for any host PID of a process inside a container:
#!/bin/bash -e
# Prints the name of the container inside which the process with a PID on the host is.
function getName {
local pid="$1"
if [[ -z "$pid" ]]; then
echo "Missing host PID argument."
exit 1
fi
if [ "$pid" -eq "1" ]; then
echo "Unable to resolve host PID to a container name."
exit 2
fi
# ps returns values potentially padded with spaces, so we pass them as they are without quoting.
local parentPid="$(ps -o ppid= -p $pid)"
local containerId="$(ps -o args= -f -p $parentPid | grep docker-containerd-shim | cut -d ' ' -f 2)"
if [[ -n "$containerId" ]]; then
local containerName="$(docker inspect --format '{{.Name}}' "$containerId" | sed 's/^\///')"
if [[ -n "$containerName" ]]; then
echo "$containerName"
else
echo "$containerId"
fi
else
getName "$parentPid"
fi
}
getName "$1"

Bash Script to execute Docker container operations and extract container IP Address

I am trying to write a Linux bash script that creates and runs docker containers that run a simple python web server, extract the container IP Address and make an HTTP Request to the server through a browser. There seem to be some mistakes in my script and I need help in editing it. I am new to bash scripting. I use Ubuntu 13.10
My Script:
#!/bin/bash
for i in {1..2}
do
echo "Creating and Running Container $i "
sudo docker run -name $i PythonServer
IP=sudo docker inspect $i | grep IPAddress | cut -d '"' -f 4
echo "Ip Address is:"
echo "${IP}"
xdg-open 'http://$IP:7111/execute'
done
EDIT: Line 6 of the code doesn't seem to be working as echo "${IP}" is giving a blank output. I want to assign the result of sudo docker inspect $i | grep IPAddress | cut -d '"' -f 4 to IP variable i.e I want to capture the IP Address of the created container and use it in xdg-open 'http://$IP:7111/execute' to make the HTTP Request dynamically. But I'm not getting the right format in which this bash script line should be written: IP=sudo docker inspect $i | grep IPAddress | cut -d '"' -f 4
And also what is the correct format in which I can use IP value in xdg-open 'http://$IP:7111/execute'
This above mentioned script presently shows this message on execution:
vishal#bl-lin-01:~/docker/PythonServer/new$ ./BashScript.sh
Creating and Running Container 1
WARNING: Docker detected local DNS server on resolv.conf. Using default external servers: [8.8.8.8 8.8.4.4]
^Cserving at port 7111
Traceback (most recent call last):
File "/scripts/InitScript.py", line 40, in <module>
httpd.serve_forever()
File "/usr/lib/python2.7/SocketServer.py", line 225, in serve_forever
r, w, e = select.select([self], [], [], poll_interval)
KeyboardInterrupt
unknown option: 1
valid options are:
-license
-copyright
-crlf
-end
-link
-path_name
-tab
-ascii
-apple_macro
-assert_macro
-minmax
-unnamed
default is all checks on; otherwise options specify desired checks
Ip Address is:
Thanks.
This Edited Bash Script works fine now..
#!/bin/bash
for i in {1..2}
do
echo "Creating and Running Container $i "
sudo docker run -d -name $i PythonServer
IP=$(sudo docker inspect $i | grep IPAddress | cut -d '"' -f 4)
echo "Ip Address is:$IP"
xdg-open "http://$IP:7111/execute"
done
I ran the containers in Daemon mode and used the Command Substitution feature of bash to assign the output of the command to variable IP
The best way to obtain docker container IP address is
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CONTAINER_NAME

Resources