Inserting a conditional RUN statement inside a dockerfile - shell

I am trying to write a docker file which will run a RUN command to search for a word in a package.json file and act upon it:
this is my simple dockerfile:
FROM ubuntu:14.04
COPY package.json package.json
RUN if grep -q "grunt" package.json; then echo succeed fi
as you can see i just want a simple if statement but it get this error:
Step 2 : RUN if grep -q "grunt" package.json; then echo succeed fi
---> Running in af460df45239
/bin/sh: 1: Syntax error: end of file unexpected (expecting "fi")
INFO[0001] The command [/bin/sh -c if grep -q "grunt" package.json; then echo succeed fi] returned a non-zero code: 2
How should i run my command?
thanks.

Just like when typing at the shell, you need either a newline or a semicolon before fi:
RUN if grep -q "grunt" package.json; then echo succeed; fi
add this ^

Related

Shell script not running as bash using Dockerfile

I need to split a comma-separated string into array and run k6 for each of the array values parallely. Since shell script doesn't support arrays, I m using bash command in the script. I am not able to run it as bash using Dockerfile in TeamCity.
Dockerfile:
FROM loadimpact/k6:0.34.1
COPY ./src/lib /lib
COPY ./src/scenarios /scenarios
COPY ./src/k6-run-all.sh /k6-run-all.sh
WORKDIR /
ENTRYPOINT []
RUN bash -c "./k6-run-all.sh"
Shell script:
#!/bin/bash
K6_RUN_OPTIONS=${K6_RUN_OPTIONS}
ENV_NAME=${ENV_NAME:-qa}
IS_TEST_RUN=${IS_TEST_RUN:-true}
SCENARIO_NAME=${SCENARIO_NAME:-"full-card-visa"}
GWC_PC_ID=${GWC_PC_ID}
IFS=',' read -r -a PCIds <<< "$GWC_PC_ID"
echo "Number of PC ids provided in environment variables=" ${#PCIds[#]}
if [[ ${#PCIds[#]} > 0 ]]; then
for pcId in "$#"
do
ENV_NAME=$ENV_NAME RUN_OPTIONS=$SCENARIO_NAME-$ENV_NAME$OPTIONS_VARIANT GWC_PC_ID=$pcId k6 run $K6_RUN_OPTIONS ''$SCENARIO/index.js'' &
done
fi
existCode=$?
if [ $existCode -ne 0 ]; then
echo "Scenario $SCENARIO_NAME completed with the error"
exit $existCode
fi
Error:
#9 [5/6] RUN bash -c "./k6-run-all.sh"
17:02:02 #9 0.356 /bin/sh: bash: not found
17:02:02 #9 ERROR: executor failed running [/bin/sh -c bash -c "./k6-run-all.sh"]: exit code: 127
17:02:02 ------
17:02:02 > [5/6] RUN bash -c "./k6-run-all.sh":
17:02:02 #9 0.356 /bin/sh: bash: not found
17:02:02 ------
17:02:02 failed to solve: executor failed running [/bin/sh -c bash -c "./k6-run-all.sh"]: exit code: 127
How to modify Dockerfile or shell script to run this shell script as bash?
Previously to run it as bash script the last line of Dockerfile used to be:
CMD ["sh", "-c", "./k6-run-all.sh"]
******* Edit: **********
Updated full script after knittl's answer (current issue is after adding & for parallel runs it is not working, it is not running anything inside the for loop and it is not giving any extra error or information in logs, it is like it is skipping it):
K6_RUN_OPTIONS=${K6_RUN_OPTIONS}
ENV_NAME=${ENV_NAME:-qa}
IS_TEST_RUN=${IS_TEST_RUN:-true}
SCENARIO_NAME=${SCENARIO_NAME:-"full-card-visa"}
GWC_PC_ID=${GWC_PC_ID}
OPTIONS_VARIANT=""
if $IS_TEST_RUN; then
OPTIONS_VARIANT="-test"
fi
SCENARIO_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
SCENARIO_PATH="${SCENARIO_DIR}/scenarios"
SCENARIO="${SCENARIO_PATH}/${SCENARIO_NAME}"
echo "Executing scenario path $SCENARIO"
SCENARIO_NAME=${SCENARIO:${#SCENARIO_PATH}+1:${#SCENARIO}}
echo "Scenario Name: $SCENARIO_NAME"
echo "Run option: $SCENARIO_NAME-$ENV_NAME$OPTIONS_VARIANT"
echo "pc ids provided in environment variable=" $GWC_PC_ID
if [ -z "$GWC_PC_ID" ]
then
ENV_NAME=$ENV_NAME RUN_OPTIONS=$SCENARIO_NAME-$ENV_NAME$OPTIONS_VARIANT k6 run $K6_RUN_OPTIONS ''$SCENARIO/index.js''
else
for pcId in $(printf '%s' "$GWC_PC_ID" | tr , ' ');
do
ENV_NAME=$ENV_NAME RUN_OPTIONS=$SCENARIO_NAME-$ENV_NAME$OPTIONS_VARIANT GWC_PC_ID=$pcId k6 run $K6_RUN_OPTIONS ''$SCENARIO/index.js'' &
done
fi
existCode=$?
if [ $existCode -ne 0 ]; then
echo "Scenario $SCENARIO_NAME completed with the error"
exit $existCode
fi
k6 Docker containers do not come with bash preinstalled, but with busybox. I see two options:
Create your own Docker image based off grafana/k6 and manually install bash in your image.
Rewrite your script to not rely on bashisms. Should be fairly easy: split your list of tests to run into one path per line and while read -r path; do …; done them.
Or if support for whitespace in filenames is not required, then for path in $(printf '%s' "$GWC_PC_ID" | tr , ' '); do …; done
Note that your current script will return with the exit code of your last k6 process, meaning that if any other test failed but the last one was successfull, that will mask the error.
PS. Time to upgrade your base Docker image too. loadimpact/k6:0.34.1 is really old (exactly 1 year). It's better to switch to grafana/k6:0.40.0, which was released a week ago.

Adding arguments for batch script in command line

I'm trying to call arguments for running a script with the rsync command. I've tried various forms and this is the most "simple", however I continue to get an error.
(bash.sh)
#! /bin/bash
root_dir = $1
target_dir = $2
rsync -avh -P --stats $root_dir $target_dir
echo "Files Transferred!"
ErrorMessage
test.sh: line 2: root_dir: command not found
test.sh: line 3: target_dir: command not found
Command Line
sh bash.sh ./path_root_dir ./path_target_dir
Using a variable with a space, without using speech marks or a quote on each side can cause an error to occur, especially when the variable is used and there was a space in the value.
Another way you could try is to use an array, the options variable is where the array is, and then it is called in the rsync command below,
directory="/etc"
backupDirectory="/backup"
incrementalBackup="/incremental"
options=(-a -e 'ssh -p 10022' -b --backup-dir="$incrementalBackup" --delete)
# rsync
rsync "${options[#]}" user#server:"$directory" "$backupDirectory"

Linux Bash Shell Custom Error Message

I'm trying to spew a custom error message using the following 1 liner bash shell command. I'm not getting the "errorMessage" var set. However if I run the command individually, I'm able to capture the error message into $errorMessage variable. What am I missing?
Command:
[ "errorMessage=$(mkdir -p /path/to/restricted/folder 2>&1)" ] && echo "Something Went Wrong; Error is: ${errorMessage}"
Trials/Output:
$ [ "errorMessage=$(mkdir -p /path/to/restricted/folder 2>&1)" ] && echo "Something Went Wrong; Error is: ${errorMessage}"
Something Went Wrong; Error is:
$ echo $errorMessage
$ errorMessage=$(mkdir -p /path/to/restricted/folder 2>&1)
$ echo $errorMessage
mkdir: cannot create directory `/path': Permission denied
[ is the command named test; when not given an argument specifying an individual test to run, the default is -n (testing whether a string is empty). This code is testing whether the string "errorMessage=" (possibly with a suffix from the stderr of mkdir) is empty or not; since it contains a fixed prefix, it will never be empty, whether any error was emitted or not.
If you want to actually assign a value to the variable, that would instead look like:
errorMessage=$(mkdir -p /path/to/restricted/folder 2>&1) \
|| echo "Something Went Wrong; Error is: ${errorMessage}"
This is checking the exit status of mkdir, and running the echo should that be nonzero.

Understanding Bash if statement that invokes a command

Does anyone know what this is doing:
if ! /fgallery/fgallery -v -j3 /images /usr/share/nginx/html/ "${GALLERY_TITLE:-Gallery}"; then
mkdir -p /usr/share/nginx/html
I understand the first part is saying if /fgallery/fgallery directory doesn't exist but after this it it not clear for me.
In Bash, we can build an if based on the exit status of a command this way:
if command; then
echo "Command succeeded"
else
echo "Command failed"
fi
then part is executed when the command exits with 0 and else part otherwise.
Your code is doing exactly that.
It can be rewritten as:
/fgallery/fgallery -v -j3 /images /usr/share/nginx/html/ "${GALLERY_TITLE:-Gallery}"; fgallery_status=$?
if [ "$fgallery_status" -ne 0 ]; then
mkdir -p /usr/share/nginx/html
fi
But the former construct is more elegant and less error prone.
See these posts:
How to conditionally do something if a command succeeded or failed
Why is testing "$?" to see if a command succeeded or not, an antipattern?

Error when passing argument to a command in a bash script

I would like to execute a command like this:
#!/bin/sh
`which rvmsudo` `which program` argument
but I get this issue
/usr/bin/env: argument: No such file or directory
Make sure, all of the which statements return valid:
#!/bin/bash
RVMSUDO=`which rvmsudo`
test -z "$RCMSUDO" && exit 1
PROGRAM=`which program`
test -z "$PROGRAM" && exit 2
$RVMSUDO $PROGRAM argument

Resources