6

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.
    – Bodo
    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.
    – robbie70
    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.
    – Bodo
    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.
    – robbie70
    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 ${...}
    – Bodo
    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.
    – robbie70
    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.
    – robbie70
    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.
    – robbie70
    Commented May 29, 2019 at 7:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .