7

I am trying to create a Makefile target which first checks to see if my Docker container exists. If it exists then I want to issue the Docker Container Restart command otherwise I want to issue the Docker Run command to create and start the container.

I have coded the below but am getting the error shown below. The result = 1 is correct as I do have a container running. I have removed the container and tested that the result then becomes 0 which is also correct. The problem seems to be when I try to use result in the ifeq statement. Can someone please advise me what I am doing wrong? (I have temporarily commented out the docker commands and replaced them with echo true / false just while I am debugging).

start_docker_myapp:
    result = $(shell (docker ps -a | grep myapp ) | wc -l )
    ifeq (${result}, 1)
        @echo 'true'
# docker restart ${IMAGE}
    else
        @echo 'false'
# docker run -v ${DIR}/var/log/docker:/var/log/myapp -p 1812:1812/udp  -p 1813:1813/udp --detach  --name ${IMAGE} $(REGISTRY)/$(IMAGE):$(TAG)
    endif

Output from Terminal

$ make start_docker_myapp
result =        1
make: result: No such file or directory
make: *** [start_docker_myapp] Error 1
$
5
  • Why do you want to implement this in a Makefile? The main purpose of make is to run commands depending on comparisons of file modification dates. You don't do this in your Makefile. A shell script (or a set of shell scripts) might be better suited for your use case. Commented May 28, 2019 at 14:49
  • @Bodo - thanks for your comment. I am using Jenkins. I was going try to do this in my Jenkinsfile but I read a comment that that wasnt the place for it either - so thought I would delegate this to a Makefile. Commented May 28, 2019 at 15:02
  • Your commands contain both shell variables like ${IMAGE} and Make variables like $(IMAGE). Do you intend to use Make variables? You should show how you define these variables. Commented May 28, 2019 at 15:27
  • @Bodo yes I define the Make variables at the top of the script and yes I take one of the shell variables and do some manipulation on it to create the Make variables..this works ok. Commented May 29, 2019 at 7:41
  • Without seeing how you define the variables it is impossible to tell if your code is correct with respect to using $(...) or ${...} Commented May 29, 2019 at 11:00

3 Answers 3

4

There are a number of issues with your Makefile (beyond the question of whether a Makefile is the appropriate solution):

  • conditional directives aren’t part of a recipe, so they mustn’t start with a tab;
  • conditional directives are evaluated as the Makefile is read, so variables must be assigned previously and can’t be target-specific;
  • docker ps -a returns information on all known containers, including non-running containers;
  • phony targets should be declared as such.

The following works:

result = $(shell docker ps -f name=myapp -q | wc -l)
start_docker_myapp:
ifeq ($(strip $(result)),1)
    @echo true
else
    @echo false
endif

.PHONY: start_docker_myapp
1
  • thank you for this this is very helpful - also your explanation as I was struggling to follow the GNU documentation. I will try your script. Also I would be grateful for any suggestions you might have for a good documentation / tutorial. Commented May 29, 2019 at 7:42
1

To set a variable value inside a target, you must use the eval syntax:

start_docker_myapp:
    $(eval result = $(shell (docker ps -a | grep myapp ) | wc -l ))
    @echo "result is " result
    endif

Alternatively, you can evaluate this variable outside a rule:

result = $(shell (docker ps -a | grep myapp ) | wc -l )

start_docker_myapp:        
    @echo "result is " result
    endif
1
  • thank you for the explanation and example this is also very helpful. Commented May 29, 2019 at 7:43
1

Instead of implementing a mix of shell script code and make variables I suggest to implement this as a pure shell script integrated in the Makefile.

Instead of checking the output of grep with wc and comparing the number you can simply check grep's exit code.

# don't forget to declare start_docker_myapp as a phony target
.PHONY: start_docker_myapp

# Assuming you intended to use Make variables everywhere, I changed all ${VAR} to $(VAR).
# If your grep supports option -q you can use this instead of redirection to /dev/null.

start_docker_myapp:
    if docker ps -a | grep myapp >/dev/null; \
    then \
        echo 'true'; \
        # docker restart $(IMAGE); \
    else \
        echo 'false'; \
        # docker run -v $(DIR)/var/log/docker:/var/log/myapp -p 1812:1812/udp  -p 1813:1813/udp --detach  --name $(IMAGE) $(REGISTRY)/$(IMAGE):$(TAG); \
    fi

Or with boolean operators instead of if...then...

.PHONY: start_docker_myapp

start_docker_myapp:
    docker ps -a | grep myapp >/dev/null && docker restart $(IMAGE) || docker run -v $(DIR)/var/log/docker:/var/log/myapp -p 1812:1812/udp  -p 1813:1813/udp --detach  --name $(IMAGE) $(REGISTRY)/$(IMAGE):$(TAG)
1
  • thank you for this. I will take a look at this as well. Commented May 29, 2019 at 7:47

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.