Docker run with if statement within Docker Bamboo Task - bash

I would like to run a docker openjdk:8-jdk with the following command:
if [ "$GIT_BRANCH" = "master" ]; then ./gradlew publish; else echo Skipped because it is not master branch; fi
I tried to do the following:
docker run --rm openjdk:8-jdk "if [ \"$GIT_BRANCH\" = \"master\" ]; then echo hi; else echo bla; fi"
But I get the following error: executable file not found in $PATH": unknown.
Furthermore it is not possible for me that I use the if statement like that:
if ...
docker run ...
else
echo Skipped
Because I have to run it as a bamboo docker task.

Since the command above is not executed within bash, bash has to be started first like that:
docker run --rm openjdk:8-jdk /bin/bash -c "if [ \"$GIT_BRANCH\" = \"master\" ]; then ./gradlew publish; else echo Skipped because it is not master branch; fi"

Related

How to quote entrypoint argument when updating a docker service

I've a small script to update some services in my docker stack.
The problem is that I'm not able to update the entrypoint of a service.
For example, my script generates the following command :
docker service update --entrypoint 'go run main.go web' myservice:latest
If a run this command in my terminal it works like a charm but when the command is launched by my script I get the following error:
invalid argument "'go" for "--entrypoint" flag: EOF found when expecting closing quote
Here are the interesting lines in my script :
CMD="go run main web"
...
if [ -n "$CMD" ]; then
update="--entrypoint '${CMD}'"
fi
if [ -n "$update" ]; then
docker service update $update $fullname
echo "docker service update $update $fullname" // output => docker service update --entrypoint 'go run main.go web' myservice:latest
fi
Any help is welcome.
The problem is with your script. Using update as you are, you are running the following
docker service update --entrypoint \'go run main web\'
not
docker service update --entrypoint 'go run main web'
Use an array to store the arguments instead
CMD="go run main web"
if [ -n "$CMD" ]; then
update=(--entrypoint "$CMD")
fi
if [ -n "$update" ]; then # Really just checks ${update[0]}, but that's sufficient
docker service update "${update[#]}" "$fullname"
echo "docker service update ${update[*]} $fullname"
fi
Alternatively, you can test CMD directly to decide if you want to run the command with the --entrypoint option at all.
CMD="go run main web"
if [ -n "$CMD" ]; then
docker service update --entrypoint "$CMD" "$fullname"
echo "docker service --entrypoint $CMD $fullname"
fi

How to do try and catch in bash file?

I have shell file (deploy.sh) do the following commands:
npm run build:prod
docker-compose -f .docker/docker-compose.ecr.yml build my-app
docker-compose -f .docker/docker-compose.ecr.yml push my-app
aws ecs update-service --cluster ...
I want to stop the execution of the bash when error occurred from one of the commands.
Which command does that in shell?
If you want to test the success or failure of a command, you can rely on its exit code. Knowing that each command will return a 0 on success or any other number on failure, you have a few options on how to handle each command's errors.
|| handler
npm run build:prod || exit 1
if condition
if docker-compose -f .docker/docker-compose.ecr.yml build my-app; then
printf "success\n"
else
printf "failure\n"
exit 1
fi
the $? variable
docker-compose -f .docker/docker-compose.ecr.yml push my-app
if [ $? -gt 0 ]; then
printf "Failure\n"
exit 1
fi
traps
err_report() {
echo "Error on line $1"
}
trap 'err_report $LINENO' ERR
aws ecs update-service --cluster ...
set -e
To globally "exit on error", then set -e will do just that. It won't give you much info, but it'll get the job done.
You can use set -e to exit on errors. And even better, you can set -e and use a trap function.
#!/bin/bash
set -e
trap 'catch $? $LINENO' EXIT
catch() {
echo "catching!"
if [ "$1" != "0" ]; then
# error handling goes here
echo "Error $1 occurred on $2"
fi
}
npm run build:prod
docker-compose -f .docker/docker-compose.ecr.yml build my-app
docker-compose -f .docker/docker-compose.ecr.yml push my-app
aws ecs update-service --cluster ...
source: https://medium.com/#dirk.avery/the-bash-trap-trap-ce6083f36700
Did a fast search on Google and it seems there isnt. Best is to use && or || or if ... else blocks see links below:
SO-Try Catch in bash
and
Linuxhint
Hope this helps

How to run command conditionally in docker compose

I want to run command conditionally in docker-compose
because when someone run this application at first time,
They would have to run migrate command so that they can run django application properly
But If their docker have run migrate, there is no need to run migrate again
So this is the command to check that their docker have run migrate.
if [[ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]]; then
echo 'no need to migrate'
else
echo 'need to migate'
fi
This is my docker-compose.
version: '3'
services:
db:
image: postgres
web:
command: >
bash -c "if [[ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]]; then
echo 'no need to migrate'
else
echo 'need to migate'
fi && python3 zeus/manage.py runserver 0.0.0.0:8000
"
But Error occurs like this
ERROR: Invalid interpolation format for "build" option in service
"web": "bash -c "if [[ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]]; then
echo 'no need to migrate' else echo 'need to migate' fi
&& python3 zeus/manage.py runserver 0.0.0.0:8000""
Any idea?
Edit
This is fine when I run the script of checking migration in normal bash
I think docker-compose can't parse $(python3 manage.py .....) part.
try this :
version: '3'
services:
db:
image: postgres
web:
command: bash -c "if [[ -z $$(python3 zeus/manage.py showmigrations | grep '\\[ \\]') ]]; then
echo 'no need to migrate';
else
echo 'need to migate';
fi && python3 zeus/manage.py runserver 0.0.0.0:8000"
three problems were there , you need to escap the escape charachter \ and add more $ to escape the replacment in compose and one more space before the last ]]
Try to avoid writing complicated scripts in docker-compose.yml, especially if they're for normal parts of your application setup.
A typical pattern is to put this sort of setup in an entrypoint script. That script ends with the shell command exec "$#". In a Docker context, that tells it to replace itself with the command (from a Dockerfile CMD statement or Docker Compose command:). For your example this could look like
#!/bin/sh
if [ -z $(python3 zeus/manage.py showmigrations | grep '\[ \]')]; then
echo 'no need to migrate'
else
echo 'need to migate'
fi
exec "$#"
Then in your Dockerfile, copy this file in and specify it as the ENTRYPOINT; leave your CMD that runs your application unmodified.
COPY entrypoint.sh /app
RUN chmod +x entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
CMD python3 zeus/manage.py run --host=0.0.0.0:8000
The ENTRYPOINT statement must be the JSON-array form and must not have an explicit sh -c wrapper in it.
If you want to verify that things have gotten set up correctly, you can run
docker-compose run web sh
and you will get a shell at the point that exec "$#" is: after your migrations and other setup have run, but instead of your main server process.

Docker Check if DB is Running

entrypoint.sh contains various cqlsh commands that require Cassandra. Without something like script.sh, cqlsh commands fail because Cassandra doesn't have enough time to start. When I execute the following locally, everything appears to work properly. However, when I run via Docker, script.sh never finishes. In other words, $status never changes from 1 to 0.
Dockerfile
FROM cassandra
RUN apt-get update && apt-get install -y netcat
RUN mkdir /dir
ADD ./scripts /dir/scripts
RUN /bin/bash -c 'service cassandra start'
RUN /bin/bash -c '/dir/scripts/script.sh'
RUN /bin/bash -c '/dir/scripts/entrypoint.sh'
script.sh
#!/bin/bash
set -e
cmd="$#"
status=$(nc -z localhost 9042; echo $?)
echo $status
while [ $status != 0 ]
do
sleep 3s
status=$(nc -z localhost 9042; echo $?)
echo $status
done
exec $cmd
Alternatively, I could do something like until cqlsh -e 'some code'; do .., as noted here for psql, but that doesn't appear to work for me. Wondering how best to approach the problem.
You're misusing the RUN command in your Dockerfile. It's not for starting services, it's for making filesystem changes in your image. The reason $status doesn't update is because you can't start Cassandra via a RUN command.
You should add service cassandra start and /dir/scripts/entrypoint.sh to your script.sh file, and make that the CMD that's executed by default:
Dockerfile
CMD ['/bin/bash', '-c', '/dir/scripts/script.sh']
script.sh
#!/bin/bash
set -e
# NOTE: I removed your `cmd` processing in favor of invoking entrypoint.sh
# directly.
# Start Cassandra before waiting for it to boot.
service cassandra start
status=$(nc -z localhost 9042; echo $?)
echo $status
while [ $status != 0 ]
do
sleep 3s
status=$(nc -z localhost 9042; echo $?)
echo $status
done
exec /bin/bash -c /dir/scripts/entrypoint.sh

TravisCI build succeeds even when tests fail

This is where I am running my tests in travis.yml:
# Run tests
script:
# Test application in Docker container
- ./tools/docker-test.sh
The shell script docker-test.sh looks like this:
#!/usr/bin/env bash
githash="$(git rev-parse --short HEAD)"
echo "-------------------------------------------------"
echo "| Running unit tests |"
echo "-------------------------------------------------"
docker create -it --name test eu.gcr.io/test/test:$githash
docker start test
docker exec test /bin/sh -c "go test ./..."
docker stop test
docker rm -fv test
The TravisCI build is a success even if the tests fail.
How can I get TravisCI to know if test have failed or not? I don't know if this is a problem with errors not being propagated from Docker, errors not being propagated from the shell script or TravisCI not knowing when go tests succeed or fail.
Your script is exiting with the status code of the last command docker rm -fv test.
You need to capture the status code of the test's, then clean up docker, then exit.
This code example is from a slightly different question over here but it's the same solution.
#!/usr/bin/env bash
set -e
# Set a default return code
RC=2
# Cleanup
function cleanup {
echo "Removing container"
docker stop test || true
docker rm -f test || true
exit $RC
}
trap cleanup EXIT
# Test steps
docker create -it --name test path
docker start test
docker exec test /bin/sh -c "go test ./..."
RC=$?

Resources