|
| 1 | +SHELL := bash |
| 2 | +AGENT_NAME := $(shell python3 -c "import re; print(re.search(r'^name:\s*(.+)', open('agent.yaml').read(), re.M).group(1).strip())") |
| 3 | +CHART_DIR := ../../../charts/agent |
| 4 | +VALUES_FILE := values.yaml |
| 5 | +CONTAINER_CLI := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null) |
| 6 | + |
| 7 | +.PHONY: init run run-cli build push build-openshift deploy undeploy test dry-run help |
| 8 | + |
| 9 | +help: ## Show this help |
| 10 | + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-12s %s\n", $$1, $$2}' |
| 11 | + |
| 12 | +init: ## Copy .env.example to .env for configuration |
| 13 | + @if [ ! -f .env ]; then cp .env.example .env && echo "Created .env from .env.example — edit it with your configuration"; else echo ".env already exists — skipping"; fi |
| 14 | + |
| 15 | +run: ## Run agent locally with hot-reload |
| 16 | + @set -a && source .env && set +a && \ |
| 17 | + uv run uvicorn main:app --host 0.0.0.0 --port $${PORT:-8000} --reload --reload-exclude .venv |
| 18 | + |
| 19 | +run-cli: ## Run interactive CLI chat (no web server) |
| 20 | + @set -a && source .env && set +a && \ |
| 21 | + cd examples && uv run python execute_ai_service_locally.py |
| 22 | + |
| 23 | +build: ## Build container image locally (podman/docker) |
| 24 | + @[ -n "$(CONTAINER_CLI)" ] || { echo "ERROR: neither podman nor docker found in PATH"; exit 1; } && \ |
| 25 | + source .env && \ |
| 26 | + [ -n "$${CONTAINER_IMAGE}" ] || { echo "ERROR: CONTAINER_IMAGE is not set in .env"; exit 1; } && \ |
| 27 | + cp -r ../../../images ./images && trap 'rm -rf ./images' EXIT && \ |
| 28 | + $(CONTAINER_CLI) build --platform linux/amd64 -t "$${CONTAINER_IMAGE}" -f Dockerfile . |
| 29 | + |
| 30 | +push: ## Push container image to registry |
| 31 | + @[ -n "$(CONTAINER_CLI)" ] || { echo "ERROR: neither podman nor docker found in PATH"; exit 1; } && \ |
| 32 | + source .env && \ |
| 33 | + [ -n "$${CONTAINER_IMAGE}" ] || { echo "ERROR: CONTAINER_IMAGE is not set in .env"; exit 1; } && \ |
| 34 | + $(CONTAINER_CLI) push "$${CONTAINER_IMAGE}" |
| 35 | + |
| 36 | +build-openshift: ## Build image in-cluster via OpenShift BuildConfig (no podman/docker needed) |
| 37 | + @cp -r ../../../images ./images && trap 'rm -rf ./images' EXIT && \ |
| 38 | + oc new-build --strategy=docker --binary --name=$(AGENT_NAME) --to=$(AGENT_NAME):latest 2>/dev/null || true && \ |
| 39 | + oc start-build $(AGENT_NAME) --from-dir=. --follow && \ |
| 40 | + NS=$$(oc project -q) && \ |
| 41 | + echo "" && \ |
| 42 | + echo "Image built. To deploy, set in .env:" && \ |
| 43 | + echo " CONTAINER_IMAGE=image-registry.openshift-image-registry.svc:5000/$$NS/$(AGENT_NAME):latest" |
| 44 | + |
| 45 | +_check-env: |
| 46 | + @set -a && source .env 2>/dev/null && set +a; \ |
| 47 | + missing=""; \ |
| 48 | + for var in $$(sed -n '/^ *required:/,/^ *[a-z]/{ /^ *- /s/^ *- *//p; }' agent.yaml); do \ |
| 49 | + eval val="\$$$$var"; \ |
| 50 | + [ -n "$$val" ] || missing="$$missing $$var"; \ |
| 51 | + done; \ |
| 52 | + [ -z "$$missing" ] || { echo "ERROR: Missing required env vars:$$missing"; exit 1; } |
| 53 | + |
| 54 | +deploy: _check-env ## Deploy to OpenShift/K8s via Helm |
| 55 | + @source .env && \ |
| 56 | + [ -n "$${CONTAINER_IMAGE}" ] || { echo "ERROR: CONTAINER_IMAGE is not set in .env"; exit 1; } && \ |
| 57 | + case "$${CONTAINER_IMAGE}" in *:*) IMAGE_REPO="$${CONTAINER_IMAGE%:*}"; IMAGE_TAG="$${CONTAINER_IMAGE##*:}";; *) IMAGE_REPO="$${CONTAINER_IMAGE}"; IMAGE_TAG="latest";; esac && \ |
| 58 | + trap 'rm -f .helm-secrets.yaml' EXIT && \ |
| 59 | + umask 077 && \ |
| 60 | + { printf 'secrets:\n apiKey: "%s"\n' "$${API_KEY}"; \ |
| 61 | + [ -z "$${MLFLOW_TRACKING_TOKEN}" ] || printf ' mlflowTrackingToken: "%s"\n' "$${MLFLOW_TRACKING_TOKEN}"; \ |
| 62 | + } > .helm-secrets.yaml && \ |
| 63 | + helm upgrade --install $(AGENT_NAME) $(CHART_DIR) \ |
| 64 | + -f $(VALUES_FILE) \ |
| 65 | + -f .helm-secrets.yaml \ |
| 66 | + --set image.repository="$${IMAGE_REPO}" \ |
| 67 | + --set image.tag="$${IMAGE_TAG}" \ |
| 68 | + --set env.BASE_URL="$${BASE_URL}" \ |
| 69 | + --set env.MODEL_ID="$${MODEL_ID}" \ |
| 70 | + $${MLFLOW_TRACKING_URI:+--set env.MLFLOW_TRACKING_URI="$${MLFLOW_TRACKING_URI}"} \ |
| 71 | + $${MLFLOW_EXPERIMENT_NAME:+--set env.MLFLOW_EXPERIMENT_NAME="$${MLFLOW_EXPERIMENT_NAME}"} \ |
| 72 | + $${MLFLOW_TRACKING_INSECURE_TLS:+--set env.MLFLOW_TRACKING_INSECURE_TLS="$${MLFLOW_TRACKING_INSECURE_TLS}"} \ |
| 73 | + $${MLFLOW_WORKSPACE:+--set env.MLFLOW_WORKSPACE="$${MLFLOW_WORKSPACE}"} && \ |
| 74 | + if command -v oc >/dev/null 2>&1; then \ |
| 75 | + echo "" && echo "Waiting for rollout to complete..." && \ |
| 76 | + if oc rollout status deployment/$(AGENT_NAME) --timeout=120s; then \ |
| 77 | + ROUTE=$$(oc get route $(AGENT_NAME) -o jsonpath='{.spec.host}' 2>/dev/null || true); \ |
| 78 | + if [ -n "$$ROUTE" ]; then echo "" && echo "Agent is available at: https://$$ROUTE"; fi; \ |
| 79 | + else \ |
| 80 | + echo "" && echo "WARNING: Rollout did not complete successfully. Check pod status with:" && \ |
| 81 | + echo " oc get pods -l app.kubernetes.io/name=$(AGENT_NAME)" && \ |
| 82 | + echo " oc logs deployment/$(AGENT_NAME)"; \ |
| 83 | + fi; \ |
| 84 | + fi |
| 85 | + |
| 86 | +dry-run: _check-env ## Render Helm templates without deploying |
| 87 | + @source .env && \ |
| 88 | + [ -n "$${CONTAINER_IMAGE}" ] || { echo "ERROR: CONTAINER_IMAGE is not set in .env"; exit 1; } && \ |
| 89 | + case "$${CONTAINER_IMAGE}" in *:*) IMAGE_REPO="$${CONTAINER_IMAGE%:*}"; IMAGE_TAG="$${CONTAINER_IMAGE##*:}";; *) IMAGE_REPO="$${CONTAINER_IMAGE}"; IMAGE_TAG="latest";; esac && \ |
| 90 | + helm template $(AGENT_NAME) $(CHART_DIR) \ |
| 91 | + -f $(VALUES_FILE) \ |
| 92 | + --set secrets.apiKey="REDACTED" \ |
| 93 | + --set image.repository="$${IMAGE_REPO}" \ |
| 94 | + --set image.tag="$${IMAGE_TAG}" \ |
| 95 | + --set env.BASE_URL="$${BASE_URL}" \ |
| 96 | + --set env.MODEL_ID="$${MODEL_ID}" \ |
| 97 | + $${MLFLOW_TRACKING_URI:+--set env.MLFLOW_TRACKING_URI="$${MLFLOW_TRACKING_URI}"} \ |
| 98 | + $${MLFLOW_TRACKING_TOKEN:+--set secrets.mlflowTrackingToken="REDACTED"} \ |
| 99 | + $${MLFLOW_EXPERIMENT_NAME:+--set env.MLFLOW_EXPERIMENT_NAME="$${MLFLOW_EXPERIMENT_NAME}"} \ |
| 100 | + $${MLFLOW_TRACKING_INSECURE_TLS:+--set env.MLFLOW_TRACKING_INSECURE_TLS="$${MLFLOW_TRACKING_INSECURE_TLS}"} \ |
| 101 | + $${MLFLOW_WORKSPACE:+--set env.MLFLOW_WORKSPACE="$${MLFLOW_WORKSPACE}"} |
| 102 | + |
| 103 | +undeploy: ## Remove deployment from cluster |
| 104 | + helm uninstall $(AGENT_NAME) |
| 105 | + |
| 106 | +test: ## Run tests |
| 107 | + uv run --extra dev python -m pytest tests/ |
0 commit comments