DmitrySemenov
DmitrySemenov

Reputation: 10375

makefile evaluates $(eval...) first prior to multiline IF's condition in the target

My issue: Inline $(eval...) evaluated first, then "IF" is evaluated. What I expect from the SSM target is "IF condition is evaluated first and only then $(eval...)

➜ make staging ssm TARGET=i-0d334b9e3f763bfeb
if test "i-0d334b9e3f763bfeb" == "" ; then \
    echo "OK"; \
     \
     \

echo "✔ Selected desired nodegroup staging-grafana-v1"; \
    echo "✔ Selected desired instgance-id i-07cef18e93c64c795"; \
    aws ssm start-session --target i-07cef18e93c64c795; \
else \
    echo "✔ Selected desired instgance-id i-0d334b9e3f763bfeb"; \
    aws ssm start-session --target i-0d334b9e3f763bfeb; \
    fi
✔ Selected desired instgance-id i-0d334b9e3f763bfeb

Starting session with SessionId: master-admin-06c7c2b63ca2554c4
sh-4.2$ 

So I get "fzf" related functionality in the IF top block which should be skipped due to TARGET being non-null.

So essentially speaking:

.PHONY: all
.DEFAULT_GOAL := help

# ----------------------------------------------------------------------------
# Local Variables
#
# ============================================================================

help:
    @grep -E '^[\.0-9a-zA-Z_-]+:.*?## .*$$' Makefile | awk 'BEGIN {FS = ":.*?## "}; {printf "⚡ \033[34m%-15s\033[0m %s\n", $$1, $$2}'


staging: ## setup staging env (use: make staging plan)
    @echo -n
    $(eval export ENVIRONMENT=staging)

prod: ## setup prod env (use: make prod plan)
    @echo -n
    $(eval export ENVIRONMENT=prod)

.ONESHELL:
ssm:  ## start ssm sessione
    if test "$(TARGET)" == "" ; then \
        echo "OK"; \
        $(eval NG = $(shell aws ec2 describe-instances \
            --filter Name=tag:Name,Values=$(ENVIRONMENT)* \
            --query 'Reservations[].Instances[].[Tags[?Key==`Name`].Value[] | [0]]' \
            --output text \
            | fzf)) \
        $(eval INSTANCE_ID = $(shell aws ec2 describe-instances \
            --filter Name=tag:Name,Values=${NG}  \
            --query 'Reservations[].Instances[].{id: InstanceId}' \
            --output text \
            | fzf)) \

        echo "✔ Selected desired nodegroup ${NG}"; \
        echo "✔ Selected desired instgance-id ${INSTANCE_ID}"; \
        aws ssm start-session --target ${INSTANCE_ID}; \
    else \
        echo "✔ Selected desired instgance-id ${TARGET}"; \
        aws ssm start-session --target ${TARGET}; \
    fi

Upvotes: 0

Views: 162

Answers (1)

Beta
Beta

Reputation: 99172

Do not confuse Make syntax with the shell commands in a recipe. Yes, Make expands the $(eval ... function before passing the commands to the shell, even before deciding whether to run the ssm rule.

The solution is simple; there does not appear to be any reason to use eval here. The variables NG and INSTANCE_ID can be shell variables instead of Make variables.

ssm:  ## start ssm sessione
    if test "$(TARGET)" == "" ; then \
      echo "OK"; \
      NG=`aws ec2 describe-instances \
        --filter Name=tag:Name,Values=$(ENVIRONMENT)* \
        --query 'Reservations[].Instances[].[Tags[?Key==`Name`].Value[] | [0]]' \
        --output text \
        | fzf`; \
      INSTANCE_ID=`aws ec2 describe-instances \
        --filter Name=tag:Name,Values=$$NG  \
        --query 'Reservations[].Instances[].{id: InstanceId}' \
        --output text \
        | fzf`; \
      echo "✔ Selected desired nodegroup $$NG"; \
      echo "✔ Selected desired instgance-id $$INSTANCE_ID"; \
      aws ssm start-session --target $$INSTANCE_ID; \
    else \
      echo "✔ Selected desired instgance-id ${TARGET}"; \
      aws ssm start-session --target ${TARGET}; \
    fi

(P.S. If you were planning to use those variables later in other rules, then the if-then-else which assigns the values should be outside the rule and written in Make syntax.)

Upvotes: 1

Related Questions