agent-factory: generate agent auto-retrieve-files-from-a-reposito
This commit is contained in:
1
.image-version
Normal file
1
.image-version
Normal file
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY app/ ./app/
|
||||
|
||||
RUN useradd -m -u 1001 appuser && \
|
||||
chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/health || exit 1
|
||||
|
||||
CMD ["uvicorn", "app.agent:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
148
app/agent.py
Normal file
148
app/agent.py
Normal file
@@ -0,0 +1,148 @@
|
||||
"""
|
||||
AutoRetrieveFilesFromAReposito Agent — auto-generated by Agent Factory.
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
import click
|
||||
import httpx
|
||||
import uvicorn
|
||||
from contextlib import asynccontextmanager
|
||||
from dotenv import load_dotenv
|
||||
from langchain_core.rate_limiters import InMemoryRateLimiter
|
||||
from langchain_openai import AzureChatOpenAI
|
||||
|
||||
from starlette.applications import Starlette
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
from starlette.routing import Route
|
||||
|
||||
from app.config import (
|
||||
AGENT_SELF_URL,
|
||||
AZURE_OPENAI_API_KEY,
|
||||
AZURE_OPENAI_API_VERSION,
|
||||
AZURE_OPENAI_DEPLOYMENT,
|
||||
AZURE_OPENAI_ENDPOINT,
|
||||
LOG_LEVEL,
|
||||
REGISTRY_URL,
|
||||
)
|
||||
from app.skills import AGENT_CONFIG, AUTO_RETRIEVE_FILES_FROM_A_REPOSITO_SKILLS
|
||||
from app.workflows.auto_retrieve_files_from_a_reposito_workflow import create_auto_retrieve_files_from_a_reposito_workflow
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# ── Logging ──────────────────────────────────────────────────────────────
|
||||
logging.basicConfig(
|
||||
level=getattr(logging, LOG_LEVEL.upper(), logging.INFO),
|
||||
format="%(asctime)s %(name)s %(levelname)s %(message)s",
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# ── LLM ──────────────────────────────────────────────────────────────────
|
||||
rate_limiter = InMemoryRateLimiter(
|
||||
requests_per_second=10 / 60,
|
||||
check_every_n_seconds=0.1,
|
||||
max_bucket_size=10,
|
||||
)
|
||||
|
||||
llm = AzureChatOpenAI(
|
||||
temperature=0,
|
||||
azure_deployment=AZURE_OPENAI_DEPLOYMENT,
|
||||
api_version=AZURE_OPENAI_API_VERSION,
|
||||
azure_endpoint=AZURE_OPENAI_ENDPOINT or "",
|
||||
api_key=AZURE_OPENAI_API_KEY or "",
|
||||
max_retries=5,
|
||||
timeout=120,
|
||||
rate_limiter=rate_limiter,
|
||||
)
|
||||
|
||||
workflow = create_auto_retrieve_files_from_a_reposito_workflow(llm)
|
||||
|
||||
|
||||
# ── Endpoints ────────────────────────────────────────────────────────────
|
||||
|
||||
async def health_check(request: Request) -> JSONResponse:
|
||||
return JSONResponse({"status": "healthy", "agent": 'AutoRetrieveFilesFromAReposito'})
|
||||
|
||||
|
||||
async def agent_manifest(request: Request) -> JSONResponse:
|
||||
"""GET /.well-known/agent.json"""
|
||||
return JSONResponse({
|
||||
"name": AGENT_CONFIG["name"],
|
||||
"version": AGENT_CONFIG["version"],
|
||||
"description": AGENT_CONFIG["description"],
|
||||
"url": "/",
|
||||
"skills": [
|
||||
{
|
||||
"id": s.id,
|
||||
"name": s.name,
|
||||
"description": s.description,
|
||||
"tags": s.tags,
|
||||
"inputSchema": AGENT_CONFIG.get("input_schema"),
|
||||
"outputSchema": AGENT_CONFIG.get("output_schema"),
|
||||
} for s in AUTO_RETRIEVE_FILES_FROM_A_REPOSITO_SKILLS
|
||||
],
|
||||
"capabilities": AGENT_CONFIG["capabilities"],
|
||||
})
|
||||
|
||||
|
||||
async def process_endpoint(request: Request) -> JSONResponse:
|
||||
"""POST /process — run the agent workflow."""
|
||||
try:
|
||||
body = await request.json()
|
||||
result = await workflow.ainvoke(body)
|
||||
return JSONResponse(result)
|
||||
except Exception as exc:
|
||||
logger.error("Processing failed: %s", exc, exc_info=True)
|
||||
return JSONResponse({"error": str(exc)}, status_code=500)
|
||||
|
||||
|
||||
# ── Self-registration ────────────────────────────────────────────────────
|
||||
|
||||
async def _register_with_registry():
|
||||
if not REGISTRY_URL:
|
||||
logger.info("REGISTRY_URL not set — skipping self-registration")
|
||||
return
|
||||
await asyncio.sleep(2)
|
||||
url = f"{REGISTRY_URL.rstrip('/')}/agents/register-url"
|
||||
for attempt in range(3):
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
resp = await client.post(url, json={"endpoint": AGENT_SELF_URL})
|
||||
if resp.status_code in (200, 201):
|
||||
logger.info("Self-registered with agent-registry at %s", REGISTRY_URL)
|
||||
return
|
||||
logger.warning("Registration attempt %d: HTTP %d", attempt + 1, resp.status_code)
|
||||
except Exception as exc:
|
||||
logger.warning("Registration attempt %d failed: %s", attempt + 1, exc)
|
||||
await asyncio.sleep(5)
|
||||
logger.error("Failed to self-register after 3 attempts")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app):
|
||||
task = asyncio.create_task(_register_with_registry())
|
||||
yield
|
||||
task.cancel()
|
||||
|
||||
|
||||
app = Starlette(
|
||||
routes=[
|
||||
Route("/health", methods=["GET"], endpoint=health_check),
|
||||
Route("/.well-known/agent.json", methods=["GET"], endpoint=agent_manifest),
|
||||
Route("/process", methods=["POST"], endpoint=process_endpoint),
|
||||
],
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--host", default="0.0.0.0")
|
||||
@click.option("--port", default=8080, type=int)
|
||||
def main(host: str, port: int):
|
||||
uvicorn.run(app, host=host, port=port, log_level=LOG_LEVEL.lower())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
21
app/config.py
Normal file
21
app/config.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""
|
||||
Configuration for the AutoRetrieveFilesFromAReposito agent.
|
||||
"""
|
||||
import os
|
||||
|
||||
# ── Azure OpenAI ─────────────────────────────────────────────────────────
|
||||
AZURE_OPENAI_ENDPOINT = os.getenv("AZURE_OPENAI_ENDPOINT")
|
||||
AZURE_OPENAI_API_KEY = os.getenv("AZURE_OPENAI_API_KEY")
|
||||
AZURE_OPENAI_API_VERSION = os.getenv("AZURE_OPENAI_API_VERSION", "2024-08-01-preview")
|
||||
AZURE_OPENAI_DEPLOYMENT = os.getenv("AZURE_OPENAI_DEPLOYMENT", "gpt-4o")
|
||||
|
||||
# ── Agent Registry ───────────────────────────────────────────────────────
|
||||
REGISTRY_URL = os.getenv(
|
||||
"REGISTRY_URL", "http://agent-gateway.agents.svc.cluster.local"
|
||||
)
|
||||
AGENT_SELF_URL = os.getenv(
|
||||
"AGENT_SELF_URL", "http://auto-retrieve-files-from-a-reposito.agents.svc.cluster.local"
|
||||
)
|
||||
|
||||
# ── Logging ──────────────────────────────────────────────────────────────
|
||||
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
|
||||
0
app/nodes/__init__.py
Normal file
0
app/nodes/__init__.py
Normal file
26
app/nodes/core_node.py
Normal file
26
app/nodes/core_node.py
Normal file
@@ -0,0 +1,26 @@
|
||||
async def process(state: dict) -> dict:
|
||||
"""
|
||||
This node retrieves files from a repository based on the provided URL and update scope.
|
||||
It uses an LLM to analyze and extract relevant workflow files from the repository.
|
||||
"""
|
||||
from app.agent import llm
|
||||
from langchain_core.messages import SystemMessage, HumanMessage
|
||||
|
||||
try:
|
||||
repository_url = state.get("repository_url", "")
|
||||
update_scope = state.get("update_scope", "")
|
||||
|
||||
if not repository_url or not update_scope:
|
||||
raise ValueError("Both 'repository_url' and 'update_scope' must be provided.")
|
||||
|
||||
messages = [
|
||||
SystemMessage(content="You are an assistant that retrieves workflow files from a repository."),
|
||||
HumanMessage(content=f"Repository URL: {repository_url}\nUpdate Scope: {update_scope}")
|
||||
]
|
||||
|
||||
response = await llm.ainvoke(messages)
|
||||
workflow_files = response.content.splitlines() # Assuming the LLM returns file names as newline-separated strings.
|
||||
|
||||
return {"workflow_files": workflow_files, "phase": "complete"}
|
||||
except Exception as exc:
|
||||
return {"error": str(exc), "phase": "failed"}
|
||||
29
app/skills.py
Normal file
29
app/skills.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
A2A skill declarations for AutoRetrieveFilesFromAReposito.
|
||||
"""
|
||||
from a2a.types import AgentSkill
|
||||
|
||||
|
||||
AUTO_RETRIEVE_FILES_FROM_A_REPOSITO_SKILLS = [
|
||||
AgentSkill(
|
||||
id="auto_retrieve_files_from_a_reposito_skill",
|
||||
name="AutoRetrieveFilesFromAReposito",
|
||||
description="Retrieve files from a repository",
|
||||
tags=["auto-generated"],
|
||||
examples=[],
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
AGENT_CONFIG = {
|
||||
"name": "AutoRetrieveFilesFromAReposito",
|
||||
"description": "Fetch all Java workflow files from the Gitea repository",
|
||||
"version": "1.0.0",
|
||||
"framework": "LangGraph + Starlette",
|
||||
"capabilities": {
|
||||
"streaming": False,
|
||||
"async": True,
|
||||
},
|
||||
"input_schema": {"repository_url": "string", "update_scope": "string"},
|
||||
"output_schema": {"workflow_files": "string[]"},
|
||||
}
|
||||
0
app/states/__init__.py
Normal file
0
app/states/__init__.py
Normal file
17
app/states/auto_retrieve_files_from_a_reposito_state.py
Normal file
17
app/states/auto_retrieve_files_from_a_reposito_state.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
State definitions for AutoRetrieveFilesFromAReposito agent.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict, List, Optional
|
||||
from langgraph.graph import MessagesState
|
||||
|
||||
|
||||
class AutoRetrieveFilesFromARepositoState(MessagesState):
|
||||
"""Workflow state for AutoRetrieveFilesFromAReposito."""
|
||||
# ── Input fields ─────────────────────────────────────────────────────
|
||||
pass
|
||||
# ── Output fields ────────────────────────────────────────────────────
|
||||
pass
|
||||
# ── Internal ─────────────────────────────────────────────────────────
|
||||
error: Optional[str]
|
||||
phase: str
|
||||
0
app/workflows/__init__.py
Normal file
0
app/workflows/__init__.py
Normal file
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
LangGraph workflow for AutoRetrieveFilesFromAReposito agent.
|
||||
"""
|
||||
from langgraph.graph import StateGraph, END
|
||||
|
||||
from app.states.auto_retrieve_files_from_a_reposito_state import AutoRetrieveFilesFromARepositoState
|
||||
from app.nodes.core_node import process
|
||||
|
||||
|
||||
def create_auto_retrieve_files_from_a_reposito_workflow(llm):
|
||||
"""Build and compile the AutoRetrieveFilesFromAReposito workflow graph."""
|
||||
graph = StateGraph(AutoRetrieveFilesFromARepositoState)
|
||||
|
||||
graph.add_node("process", process)
|
||||
|
||||
graph.set_entry_point("process")
|
||||
graph.add_edge("process", END)
|
||||
|
||||
return graph.compile()
|
||||
35
catalog-info.yaml
Normal file
35
catalog-info.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: auto-retrieve-files-from-a-reposito
|
||||
description: "Fetch all Java workflow files from the Gitea repository"
|
||||
annotations:
|
||||
backstage.io/kubernetes-label-selector: app=auto-retrieve-files-from-a-reposito
|
||||
backstage.io/kubernetes-namespace: agents
|
||||
backstage.io/techdocs-ref: dir:.
|
||||
gitea.kyndemo.live/repo-slug: generated-agents/auto-retrieve-files-from-a-reposito
|
||||
grafana/grafana-instance: default
|
||||
grafana/alert-label-selector: app=auto-retrieve-files-from-a-reposito
|
||||
grafana/dashboard-selector: uid == 'otel-app-observability-v2'
|
||||
grafana.com/dashboard-url: https://grafana.kyndemo.live/d/otel-app-observability-v2/opentelemetry-application-observability?orgId=1&var-app=auto-retrieve-files-from-a-reposito
|
||||
tags:
|
||||
- agent
|
||||
- a2a
|
||||
- auto-generated
|
||||
links:
|
||||
- icon: github
|
||||
title: Source Repository
|
||||
url: https://gitea.kyndemo.live/generated-agents/auto-retrieve-files-from-a-reposito
|
||||
- icon: code
|
||||
title: CI/CD Pipelines
|
||||
url: https://gitea.kyndemo.live/generated-agents/auto-retrieve-files-from-a-reposito/actions
|
||||
- icon: dashboard
|
||||
title: Grafana Dashboard
|
||||
url: https://grafana.kyndemo.live/d/otel-app-observability-v2/opentelemetry-application-observability?orgId=1&var-app=auto-retrieve-files-from-a-reposito
|
||||
spec:
|
||||
type: service
|
||||
lifecycle: experimental
|
||||
owner: group:default/agentic-agents
|
||||
system: agentic-agents
|
||||
dependsOn:
|
||||
- resource:default/cjot-aks
|
||||
13
k8s/configmap.yaml
Normal file
13
k8s/configmap.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: auto-retrieve-files-from-a-reposito-config
|
||||
namespace: agents
|
||||
data:
|
||||
REGISTRY_URL: "http://agent-gateway.agents.svc.cluster.local"
|
||||
AGENT_SELF_URL: "http://auto-retrieve-files-from-a-reposito.agents.svc.cluster.local"
|
||||
AZURE_OPENAI_DEPLOYMENT: "gpt-4o"
|
||||
AZURE_OPENAI_API_VERSION: "2024-08-01-preview"
|
||||
LOG_LEVEL: "INFO"
|
||||
OTEL_SERVICE_NAME: "auto-retrieve-files-from-a-reposito"
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-collector.monitoring.svc.cluster.local:4318"
|
||||
81
k8s/deployment.yaml
Normal file
81
k8s/deployment.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: auto-retrieve-files-from-a-reposito
|
||||
namespace: agents
|
||||
labels:
|
||||
app: auto-retrieve-files-from-a-reposito
|
||||
component: agent
|
||||
generated-by: agent-factory
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: auto-retrieve-files-from-a-reposito
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: auto-retrieve-files-from-a-reposito
|
||||
azure.workload.identity/use: "true"
|
||||
annotations:
|
||||
instrumentation.opentelemetry.io/inject-python: "monitoring/otel-instrumentation"
|
||||
spec:
|
||||
serviceAccountName: agents-sa
|
||||
containers:
|
||||
- name: auto-retrieve-files-from-a-reposito
|
||||
image: bstagecjotdevacr.azurecr.io/auto-retrieve-files-from-a-reposito:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: auto-retrieve-files-from-a-reposito-config
|
||||
env:
|
||||
- name: AZURE_OPENAI_ENDPOINT
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: agents-kv-sync
|
||||
key: azure-openai-endpoint
|
||||
- name: AZURE_OPENAI_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: agents-kv-sync
|
||||
key: azure-openai-api-key
|
||||
- name: OTEL_SERVICE_NAME
|
||||
value: "auto-retrieve-files-from-a-reposito"
|
||||
- name: OTEL_RESOURCE_ATTRIBUTES
|
||||
value: "service.namespace=agents,deployment.environment=production"
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "1Gi"
|
||||
cpu: "500m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 30
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
volumeMounts:
|
||||
- name: secrets-store
|
||||
mountPath: "/mnt/secrets-store"
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: secrets-store
|
||||
csi:
|
||||
driver: secrets-store.csi.k8s.io
|
||||
readOnly: true
|
||||
volumeAttributes:
|
||||
secretProviderClass: agents-kv-spc
|
||||
16
k8s/service.yaml
Normal file
16
k8s/service.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: auto-retrieve-files-from-a-reposito
|
||||
namespace: agents
|
||||
labels:
|
||||
app: auto-retrieve-files-from-a-reposito
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app: auto-retrieve-files-from-a-reposito
|
||||
18
requirements.txt
Normal file
18
requirements.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
# Auto-generated by Agent Factory
|
||||
uvicorn[standard]==0.32.1
|
||||
starlette>=0.28.0
|
||||
pydantic>=2.11.3
|
||||
python-dotenv==1.0.1
|
||||
httpx>=0.28.1
|
||||
click>=8.1.8
|
||||
|
||||
# A2A Protocol
|
||||
a2a-sdk[http-server]>=0.3.0
|
||||
|
||||
# LangChain & LangGraph
|
||||
langchain>=1.2.10
|
||||
langchain-openai>=0.2.12
|
||||
langchain-core>=1.2.11
|
||||
langgraph>=0.2.59
|
||||
langgraph-checkpoint>=2.0.6
|
||||
openai>=1.109.1
|
||||
54
scripts/deploy.sh
Normal file
54
scripts/deploy.sh
Normal file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
# deploy.sh — Build auto-retrieve-files-from-a-reposito image in ACR and deploy to AKS
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
ACR_NAME="bstagecjotdevacr"
|
||||
APP_NAME="auto-retrieve-files-from-a-reposito"
|
||||
NAMESPACE="agents"
|
||||
VERSION_FILE="${SCRIPT_DIR}/../.image-version"
|
||||
TAG=""
|
||||
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--tag) TAG="$2"; shift ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -z "$TAG" ]; then
|
||||
if [ -f "$VERSION_FILE" ]; then
|
||||
CURRENT_VERSION=$(cat "$VERSION_FILE")
|
||||
else
|
||||
CURRENT_VERSION="1.0.0"
|
||||
fi
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
|
||||
PATCH=$((PATCH + 1))
|
||||
TAG="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "$TAG" > "$VERSION_FILE"
|
||||
fi
|
||||
|
||||
IMAGE="${ACR_NAME}.azurecr.io/${APP_NAME}:${TAG}"
|
||||
|
||||
echo "======================================================================"
|
||||
echo " auto-retrieve-files-from-a-reposito — Build & Deploy"
|
||||
echo " Image: ${IMAGE}"
|
||||
echo "======================================================================"
|
||||
|
||||
az acr build --registry ${ACR_NAME} \
|
||||
--image ${APP_NAME}:${TAG} \
|
||||
--image ${APP_NAME}:latest \
|
||||
"${SCRIPT_DIR}/.."
|
||||
|
||||
kubectl apply -f "${SCRIPT_DIR}/../k8s/configmap.yaml" 2>/dev/null || true
|
||||
kubectl apply -f "${SCRIPT_DIR}/../k8s/deployment.yaml"
|
||||
kubectl apply -f "${SCRIPT_DIR}/../k8s/service.yaml" 2>/dev/null || true
|
||||
|
||||
kubectl set image deployment/${APP_NAME} \
|
||||
${APP_NAME}=${IMAGE} \
|
||||
-n ${NAMESPACE}
|
||||
|
||||
kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE} --timeout=120s
|
||||
|
||||
echo "✓ Done. Image: ${IMAGE}"
|
||||
echo " Port forward: kubectl port-forward -n ${NAMESPACE} deployment/${APP_NAME} 8080:8080"
|
||||
66
scripts/full-deploy.sh
Normal file
66
scripts/full-deploy.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/bin/bash
|
||||
# full-deploy.sh — Preflight + build + deploy auto-retrieve-files-from-a-reposito to AKS
|
||||
set -e
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
ACR_NAME="bstagecjotdevacr"
|
||||
APP_NAME="auto-retrieve-files-from-a-reposito"
|
||||
NAMESPACE="agents"
|
||||
VERSION_FILE="${SCRIPT_DIR}/../.image-version"
|
||||
TAG=""
|
||||
|
||||
while [[ "$#" -gt 0 ]]; do
|
||||
case $1 in
|
||||
--tag) TAG="$2"; shift ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
print_success() { echo -e "${GREEN}✓ $1${NC}"; }
|
||||
print_error() { echo -e "${RED}✗ $1${NC}"; exit 1; }
|
||||
|
||||
command -v kubectl &>/dev/null || print_error "kubectl not found."
|
||||
command -v az &>/dev/null || print_error "Azure CLI not found."
|
||||
az account show &>/dev/null || print_error "Not logged in to Azure."
|
||||
kubectl cluster-info &>/dev/null || print_error "Cannot connect to cluster."
|
||||
CLUSTER=$(kubectl config current-context)
|
||||
print_success "Connected to cluster: ${CLUSTER}"
|
||||
|
||||
if [ -z "$TAG" ]; then
|
||||
if [ -f "$VERSION_FILE" ]; then
|
||||
CURRENT_VERSION=$(cat "$VERSION_FILE")
|
||||
else
|
||||
CURRENT_VERSION="1.0.0"
|
||||
fi
|
||||
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
|
||||
PATCH=$((PATCH + 1))
|
||||
TAG="${MAJOR}.${MINOR}.${PATCH}"
|
||||
echo "$TAG" > "$VERSION_FILE"
|
||||
fi
|
||||
|
||||
IMAGE="${ACR_NAME}.azurecr.io/${APP_NAME}:${TAG}"
|
||||
print_success "Image tag: ${TAG}"
|
||||
|
||||
az acr build --registry ${ACR_NAME} \
|
||||
--image ${APP_NAME}:${TAG} \
|
||||
--image ${APP_NAME}:latest \
|
||||
"${SCRIPT_DIR}/.." || print_error "ACR build failed."
|
||||
print_success "Image built: ${IMAGE}"
|
||||
|
||||
kubectl apply -f "${SCRIPT_DIR}/../k8s/configmap.yaml" 2>/dev/null || true
|
||||
kubectl apply -f "${SCRIPT_DIR}/../k8s/deployment.yaml" || print_error "Failed to apply deployment."
|
||||
kubectl apply -f "${SCRIPT_DIR}/../k8s/service.yaml" || print_error "Failed to apply service."
|
||||
print_success "Manifests applied"
|
||||
|
||||
kubectl set image deployment/${APP_NAME} ${APP_NAME}=${IMAGE} -n ${NAMESPACE}
|
||||
kubectl rollout status deployment/${APP_NAME} -n ${NAMESPACE} --timeout=180s || \
|
||||
print_error "Rollout failed."
|
||||
print_success "Rollout complete"
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN} auto-retrieve-files-from-a-reposito deployed: ${IMAGE}${NC}"
|
||||
echo " Port forward: kubectl port-forward -n ${NAMESPACE} deployment/${APP_NAME} 8080:8080"
|
||||
Reference in New Issue
Block a user