-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathMakefile
More file actions
200 lines (185 loc) · 10.5 KB
/
Makefile
File metadata and controls
200 lines (185 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
SHELL := bash
AGENT_NAME := $(shell python3 -c "import re; print(re.search(r'^name:\s*(.+)', open('agent.yaml').read(), re.M).group(1).strip())")
CHART_DIR := ../../../charts/a2a-langgraph-crewai
VALUES_FILE := values.yaml
CONTAINER_CLI := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null)
.PHONY: init re-init env run-app run-app-fresh run-crew run-langgraph build push deploy undeploy dry-run help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-18s %s\n", $$1, $$2}'
re-init: ## Activate venv and reload .env variables
@source .venv/bin/activate && set -a && source .env && set +a && \
echo "Venv activated and .env variables loaded."
init: ## Create .env from template.env if missing
@if [ ! -f .env ]; then cp template.env .env && echo "Created .env from template.env — edit it with your configuration"; else echo ".env already exists — skipping"; fi
env: ## Create venv and install dependencies (uv sync)
@echo "==> Creating/syncing virtual environment (Python 3.12)..." && \
uv sync --python 3.12 && \
echo "" && \
echo "Done. Next: configure .env (make init), then make run-app"
run-crew: ## Run CrewAI A2A server only (CREW_A2A_PORT, default 9100)
@[ -d .venv ] || { echo "ERROR: No .venv — run: make env (or: uv venv --python 3.12 && uv sync)"; exit 1; }
@source .venv/bin/activate && set -a && source .env && set +a && \
CREW_PORT=$${CREW_A2A_PORT:-9100}; \
if command -v lsof >/dev/null 2>&1 && lsof -ti:$$CREW_PORT >/dev/null 2>&1; then \
echo "ERROR: Port $$CREW_PORT is already in use. Change CREW_A2A_PORT or run: make run-app-fresh"; \
exit 1; \
fi && \
uv run python -m a2a_langgraph_crewai.crew_a2a_server
run-langgraph: ## Run LangGraph A2A server only (LANGGRAPH_A2A_PORT, default 9200)
@[ -d .venv ] || { echo "ERROR: No .venv — run: make env (or: uv venv --python 3.12 && uv sync)"; exit 1; }
@source .venv/bin/activate && set -a && source .env && set +a && \
LG_PORT=$${LANGGRAPH_A2A_PORT:-9200}; \
if command -v lsof >/dev/null 2>&1 && lsof -ti:$$LG_PORT >/dev/null 2>&1; then \
echo "ERROR: Port $$LG_PORT is already in use. Change LANGGRAPH_A2A_PORT or run: make run-app-fresh"; \
exit 1; \
fi && \
uv run python -m a2a_langgraph_crewai.langgraph_a2a_server
run-app: ## Run both A2A servers (Crew in background, LangGraph in foreground)
@[ -d .venv ] || { echo "ERROR: No .venv — run: make env (or: uv venv --python 3.12 && uv sync)"; exit 1; }
@source .venv/bin/activate && set -a && source .env && set +a && \
CREW_PORT=$${CREW_A2A_PORT:-9100}; LG_PORT=$${LANGGRAPH_A2A_PORT:-9200}; \
if command -v lsof >/dev/null 2>&1; then \
if lsof -ti:$$CREW_PORT >/dev/null 2>&1 || lsof -ti:$$LG_PORT >/dev/null 2>&1; then \
echo "ERROR: Port $$CREW_PORT or $$LG_PORT is already in use." && \
echo " Change ports in .env or run: make run-app-fresh" && \
exit 1; \
fi; \
fi && \
echo "==> Starting Crew A2A on port $$CREW_PORT (background)..." && \
uv run python -m a2a_langgraph_crewai.crew_a2a_server & \
CREW_PID=$$! && \
trap 'kill $$CREW_PID 2>/dev/null; wait $$CREW_PID 2>/dev/null' EXIT INT TERM && \
for _ in $$(seq 1 90); do \
(echo >/dev/tcp/127.0.0.1/$$CREW_PORT) 2>/dev/null && break; \
if ! kill -0 $$CREW_PID 2>/dev/null; then \
echo "ERROR: Crew server exited before binding port $$CREW_PORT"; exit 1; \
fi; \
sleep 0.2; \
done; \
(echo >/dev/tcp/127.0.0.1/$$CREW_PORT) 2>/dev/null || { \
echo "ERROR: Crew did not listen on port $$CREW_PORT in time"; kill $$CREW_PID 2>/dev/null; exit 1; \
}; \
echo "==> Starting LangGraph A2A on port $$LG_PORT (foreground; Ctrl+C stops both)..." && \
uv run python -m a2a_langgraph_crewai.langgraph_a2a_server
run-app-fresh: ## Free default A2A ports and run both servers (see run-app)
@[ -d .venv ] || { echo "ERROR: No .venv — run: make env (or: uv venv --python 3.12 && uv sync)"; exit 1; }
@source .venv/bin/activate && set -a && source .env && set +a && \
CREW_PORT=$${CREW_A2A_PORT:-9100}; LG_PORT=$${LANGGRAPH_A2A_PORT:-9200}; \
echo "==> Killing processes on ports $$CREW_PORT and $$LG_PORT (if any)..." && \
(command -v lsof >/dev/null 2>&1 && lsof -ti:$$CREW_PORT | xargs kill -9 2>/dev/null); true && \
(command -v lsof >/dev/null 2>&1 && lsof -ti:$$LG_PORT | xargs kill -9 2>/dev/null); true && \
sleep 0.5 && \
$(MAKE) run-app
_check-env:
@set -a && source .env 2>/dev/null && set +a; \
missing=""; \
for var in $$(sed -n '/^ *required:/,/^ *[a-z]/{ /^ *- /s/^ *- *//p; }' agent.yaml); do \
eval val="\$$$$var"; \
[ -n "$$val" ] || missing="$$missing $$var"; \
done; \
[ -z "$$missing" ] || { echo "ERROR: Missing required env vars:$$missing"; exit 1; }
build: _check-env ## Build both image tags locally (same Dockerfile; second tag via tag)
@[ -n "$(CONTAINER_CLI)" ] || { echo "ERROR: neither podman nor docker found in PATH"; exit 1; }
@set -a && source .env && set +a && \
if [ -n "$${CONTAINER_IMAGE_CREW:-}" ] && [ -n "$${CONTAINER_IMAGE_LANGGRAPH:-}" ]; then \
CREW="$${CONTAINER_IMAGE_CREW}"; LG="$${CONTAINER_IMAGE_LANGGRAPH}"; \
elif [ -n "$${CONTAINER_IMAGE:-}" ]; then \
_base="$${CONTAINER_IMAGE%%@*}"; _tail="$${_base##*/}"; \
if [[ "$$_tail" == *:* ]]; then _img="$${_base%:*}"; else _img="$$_base"; fi; \
CREW="$${_img}:crew"; LG="$${_img}:langgraph"; \
else \
echo "ERROR: Set CONTAINER_IMAGE or both CONTAINER_IMAGE_CREW and CONTAINER_IMAGE_LANGGRAPH in .env"; exit 1; \
fi && \
echo "Building $$CREW (then tag -> $$LG)..." && \
$(CONTAINER_CLI) buildx build --platform linux/amd64 -t "$$CREW" -f Dockerfile . --load && \
$(CONTAINER_CLI) tag "$$CREW" "$$LG" && \
echo "Build complete: $$CREW and $$LG"
push: _check-env ## Push both image tags to the registry
@[ -n "$(CONTAINER_CLI)" ] || { echo "ERROR: neither podman nor docker found in PATH"; exit 1; }
@set -a && source .env && set +a && \
if [ -n "$${CONTAINER_IMAGE_CREW:-}" ] && [ -n "$${CONTAINER_IMAGE_LANGGRAPH:-}" ]; then \
CREW="$${CONTAINER_IMAGE_CREW}"; LG="$${CONTAINER_IMAGE_LANGGRAPH}"; \
elif [ -n "$${CONTAINER_IMAGE:-}" ]; then \
_base="$${CONTAINER_IMAGE%%@*}"; _tail="$${_base##*/}"; \
if [[ "$$_tail" == *:* ]]; then _img="$${_base%:*}"; else _img="$$_base"; fi; \
CREW="$${_img}:crew"; LG="$${_img}:langgraph"; \
else \
echo "ERROR: Set CONTAINER_IMAGE or both CONTAINER_IMAGE_CREW and CONTAINER_IMAGE_LANGGRAPH in .env"; exit 1; \
fi && \
echo "Pushing $$CREW and $$LG..." && \
$(CONTAINER_CLI) push "$$CREW" && $(CONTAINER_CLI) push "$$LG" && \
echo "Push complete."
deploy: _check-env ## Two-phase Helm deploy (Routes first, then Deployments with public Agent Card URLs)
@[ -n "$(CONTAINER_CLI)" ] || true
@set -a && source .env && set +a && \
if [ -n "$${CONTAINER_IMAGE_CREW:-}" ] && [ -n "$${CONTAINER_IMAGE_LANGGRAPH:-}" ]; then \
CREW_REPO="$${CONTAINER_IMAGE_CREW%:*}"; CREW_TAG="$${CONTAINER_IMAGE_CREW##*:}"; \
LG_REPO="$${CONTAINER_IMAGE_LANGGRAPH%:*}"; LG_TAG="$${CONTAINER_IMAGE_LANGGRAPH##*:}"; \
elif [ -n "$${CONTAINER_IMAGE:-}" ]; then \
_base="$${CONTAINER_IMAGE%%@*}"; _tail="$${_base##*/}"; \
if [[ "$$_tail" == *:* ]]; then _img="$${_base%:*}"; else _img="$$_base"; fi; \
CREW_REPO="$$_img"; CREW_TAG="crew"; LG_REPO="$$_img"; LG_TAG="langgraph"; \
else \
echo "ERROR: Set CONTAINER_IMAGE or both CONTAINER_IMAGE_CREW and CONTAINER_IMAGE_LANGGRAPH in .env"; exit 1; \
fi && \
trap 'rm -f .helm-secrets.yaml' EXIT && \
umask 077 && \
printf 'secrets:\n apiKey: "%s"\n' "$${API_KEY}" > .helm-secrets.yaml && \
echo "=== Helm phase 1: Service, Route, Secret (no Deployments yet) ===" && \
helm upgrade --install $(AGENT_NAME) $(CHART_DIR) \
-f $(VALUES_FILE) \
-f .helm-secrets.yaml \
--set deploymentsEnabled=false \
--set-string image.crew.repository="$$CREW_REPO" \
--set-string image.crew.tag="$$CREW_TAG" \
--set-string image.langgraph.repository="$$LG_REPO" \
--set-string image.langgraph.tag="$$LG_TAG" \
--set-string env.BASE_URL="$$BASE_URL" \
--set-string env.MODEL_ID="$$MODEL_ID" && \
echo "=== Waiting for OpenShift Route hostnames ===" && \
CREW_HOST=""; LG_HOST=""; \
for _ in $$(seq 1 60); do \
CREW_HOST=$$(oc get route a2a-crew-agent -o jsonpath='{.spec.host}' 2>/dev/null || true); \
LG_HOST=$$(oc get route a2a-langgraph-agent -o jsonpath='{.spec.host}' 2>/dev/null || true); \
[ -n "$$CREW_HOST" ] && [ -n "$$LG_HOST" ] && break; \
sleep 1; \
done && \
if [ -z "$$CREW_HOST" ] || [ -z "$$LG_HOST" ]; then \
echo "ERROR: Could not read route hostnames. Check: oc get route"; exit 1; \
fi && \
echo "CREW_A2A_PUBLIC_URL=https://$$CREW_HOST" && \
echo "LANGGRAPH_A2A_PUBLIC_URL=https://$$LG_HOST" && \
echo "=== Helm phase 2: Deployments with Agent Card URLs ===" && \
helm upgrade $(AGENT_NAME) $(CHART_DIR) \
-f $(VALUES_FILE) \
--reuse-values \
--set deploymentsEnabled=true \
--set-string crewPublicUrl="https://$$CREW_HOST" \
--set-string langgraphPublicUrl="https://$$LG_HOST" && \
oc rollout status deployment/a2a-crew-agent --timeout=300s && \
oc rollout status deployment/a2a-langgraph-agent --timeout=300s && \
echo "=== Done ===" && oc get route a2a-crew-agent a2a-langgraph-agent
undeploy: ## Remove Helm release (all resources)
helm uninstall $(AGENT_NAME) --ignore-not-found
dry-run: _check-env ## Render Helm manifests (secrets redacted)
@set -a && source .env && set +a && \
if [ -n "$${CONTAINER_IMAGE_CREW:-}" ] && [ -n "$${CONTAINER_IMAGE_LANGGRAPH:-}" ]; then \
CREW_REPO="$${CONTAINER_IMAGE_CREW%:*}"; CREW_TAG="$${CONTAINER_IMAGE_CREW##*:}"; \
LG_REPO="$${CONTAINER_IMAGE_LANGGRAPH%:*}"; LG_TAG="$${CONTAINER_IMAGE_LANGGRAPH##*:}"; \
elif [ -n "$${CONTAINER_IMAGE:-}" ]; then \
_base="$${CONTAINER_IMAGE%%@*}"; _tail="$${_base##*/}"; \
if [[ "$$_tail" == *:* ]]; then _img="$${_base%:*}"; else _img="$$_base"; fi; \
CREW_REPO="$$_img"; CREW_TAG="crew"; LG_REPO="$$_img"; LG_TAG="langgraph"; \
else echo "ERROR: Set CONTAINER_IMAGE or both CONTAINER_IMAGE_CREW and CONTAINER_IMAGE_LANGGRAPH"; exit 1; fi && \
helm template $(AGENT_NAME) $(CHART_DIR) \
-f $(VALUES_FILE) \
--set secrets.apiKey=REDACTED \
--set deploymentsEnabled=true \
--set-string crewPublicUrl="https://crew.example.com" \
--set-string langgraphPublicUrl="https://langgraph.example.com" \
--set-string image.crew.repository="$$CREW_REPO" \
--set-string image.crew.tag="$$CREW_TAG" \
--set-string image.langgraph.repository="$$LG_REPO" \
--set-string image.langgraph.tag="$$LG_TAG" \
--set-string env.BASE_URL="$$BASE_URL" \
--set-string env.MODEL_ID="$$MODEL_ID"