feat(infrastructure): add all 9 infrastructure scripts (00–08)
This commit is contained in:
parent
d086e9ed80
commit
5a33e8f444
33
infrastructure/00-authcheck.sh
Normal file
33
infrastructure/00-authcheck.sh
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
# 00-authcheck.sh — Verify correct gcloud identity and project before any action
|
||||
# Run in: local VS Code terminal OR Cloud Shell (identical behavior)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PROJECT_ID="${PROJECT_ID:-propane-will-491900-m5}"
|
||||
REGION="${REGION:-us-central1}"
|
||||
|
||||
echo "=== OSVauco-NMTMD-GCOS :: Auth Check ==="
|
||||
|
||||
# 1. Confirm gcloud is installed
|
||||
command -v gcloud >/dev/null 2>&1 || { echo "ERROR: gcloud CLI not found. Install from https://cloud.google.com/sdk/docs/install"; exit 1; }
|
||||
|
||||
# 2. Check active account
|
||||
ACTIVE_ACCOUNT=$(gcloud config get-value account 2>/dev/null)
|
||||
echo "Active account : $ACTIVE_ACCOUNT"
|
||||
[ -z "$ACTIVE_ACCOUNT" ] && { echo "ERROR: No active account. Run: gcloud auth login"; exit 1; }
|
||||
|
||||
# 3. Set and confirm project
|
||||
gcloud config set project "$PROJECT_ID" --quiet
|
||||
ACTIVE_PROJECT=$(gcloud config get-value project)
|
||||
echo "Active project : $ACTIVE_PROJECT"
|
||||
[ "$ACTIVE_PROJECT" != "$PROJECT_ID" ] && { echo "ERROR: Project mismatch. Expected $PROJECT_ID, got $ACTIVE_PROJECT"; exit 1; }
|
||||
|
||||
# 4. Check Application Default Credentials
|
||||
if ! gcloud auth application-default print-access-token >/dev/null 2>&1; then
|
||||
echo "WARNING: No ADC found. Run: gcloud auth application-default login"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Auth check PASSED. Project: $PROJECT_ID | Region: $REGION"
|
||||
echo "========================================"
|
||||
96
infrastructure/01-setupenv.sh
Normal file
96
infrastructure/01-setupenv.sh
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#!/bin/bash
|
||||
# 01-setupenv.sh — Enable APIs, create staging bucket with lifecycle, SA, billing budget
|
||||
# Run in: local VS Code terminal OR Cloud Shell
|
||||
# Source .env before running: source .env
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID in .env}"
|
||||
: "${REGION:?Set REGION in .env}"
|
||||
: "${BILLING_ACCOUNT_ID:?Set BILLING_ACCOUNT_ID in .env}"
|
||||
: "${AGENT_SA:?Set AGENT_SA in .env}"
|
||||
|
||||
BUCKET_NAME="gs://${PROJECT_ID}-agent-staging"
|
||||
BUDGET_NAME="OSVauco-Agent-Budget-500USD"
|
||||
|
||||
echo "=== 01: Environment Setup for ${PROJECT_ID} ==="
|
||||
|
||||
# 0. Auth check
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
|
||||
# 1. Enable required APIs (idempotent)
|
||||
echo "Enabling required APIs..."
|
||||
gcloud services enable \
|
||||
aiplatform.googleapis.com \
|
||||
storage.googleapis.com \
|
||||
cloudbilling.googleapis.com \
|
||||
cloudresourcemanager.googleapis.com \
|
||||
iam.googleapis.com \
|
||||
run.googleapis.com \
|
||||
artifactregistry.googleapis.com \
|
||||
cloudbuild.googleapis.com \
|
||||
secretmanager.googleapis.com \
|
||||
monitoring.googleapis.com \
|
||||
logging.googleapis.com \
|
||||
cloudtrace.googleapis.com \
|
||||
--project="$PROJECT_ID" --quiet
|
||||
echo "✓ APIs enabled."
|
||||
|
||||
# 2. Create staging bucket (idempotent)
|
||||
if gcloud storage ls "$BUCKET_NAME" >/dev/null 2>&1; then
|
||||
echo "✓ Staging bucket $BUCKET_NAME already exists."
|
||||
else
|
||||
gcloud storage buckets create "$BUCKET_NAME" \
|
||||
--location="$REGION" --project="$PROJECT_ID" --quiet
|
||||
echo "✓ Bucket created: $BUCKET_NAME"
|
||||
fi
|
||||
|
||||
# 3. Apply lifecycle rule (auto-delete objects >7 days)
|
||||
cat > /tmp/lifecycle.json << 'EOF'
|
||||
{"rule":[{"action":{"type":"Delete"},"condition":{"age":7}}]}
|
||||
EOF
|
||||
gcloud storage buckets update "$BUCKET_NAME" --lifecycle-file=/tmp/lifecycle.json --quiet
|
||||
echo "✓ Lifecycle rule applied (delete after 7 days)."
|
||||
|
||||
# 4. Service account (idempotent)
|
||||
SA_NAME=$(echo "$AGENT_SA" | cut -d'@' -f1)
|
||||
if ! gcloud iam service-accounts describe "$AGENT_SA" --project="$PROJECT_ID" >/dev/null 2>&1; then
|
||||
gcloud iam service-accounts create "$SA_NAME" \
|
||||
--display-name="OSVauco Agent Runner SA" --project="$PROJECT_ID" --quiet
|
||||
echo "✓ Service account created: $AGENT_SA"
|
||||
fi
|
||||
|
||||
for ROLE in \
|
||||
roles/aiplatform.user \
|
||||
roles/storage.objectAdmin \
|
||||
roles/logging.logWriter \
|
||||
roles/cloudtrace.agent \
|
||||
roles/monitoring.metricWriter \
|
||||
roles/secretmanager.secretAccessor \
|
||||
roles/run.invoker; do
|
||||
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
|
||||
--member="serviceAccount:${AGENT_SA}" --role="$ROLE" --quiet
|
||||
done
|
||||
echo "✓ IAM bindings configured."
|
||||
|
||||
# 5. Billing budget alert (idempotent check by display name)
|
||||
EXISTING=$(gcloud billing budgets list \
|
||||
--billing-account="${BILLING_ACCOUNT_ID}" \
|
||||
--filter="displayName=${BUDGET_NAME}" \
|
||||
--format="value(name)" 2>/dev/null | head -1 || true)
|
||||
|
||||
if [[ -z "${EXISTING}" ]]; then
|
||||
gcloud billing budgets create \
|
||||
--billing-account="${BILLING_ACCOUNT_ID}" \
|
||||
--display-name="${BUDGET_NAME}" \
|
||||
--budget-amount=500USD \
|
||||
--threshold-rule=percent=0.5,basis=CURRENT_SPEND \
|
||||
--threshold-rule=percent=0.8,basis=CURRENT_SPEND \
|
||||
--threshold-rule=percent=1.0,basis=CURRENT_SPEND
|
||||
echo "✓ Budget alert created"
|
||||
else
|
||||
echo "✓ Budget alert already exists"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== 01: Environment setup COMPLETE ==="
|
||||
63
infrastructure/02-deploy.sh
Normal file
63
infrastructure/02-deploy.sh
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env bash
|
||||
# 02-deploy.sh — Build and deploy orchestrator agent to Cloud Run
|
||||
# Idempotent: updates existing service if present
|
||||
# Source .env before running: source .env
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${AGENT_SA:?Set AGENT_SA}"
|
||||
: "${ARTIFACT_REPO:?Set ARTIFACT_REPO}"
|
||||
: "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE}"
|
||||
|
||||
IMAGE="${REGION}-docker.pkg.dev/${PROJECT_ID}/${ARTIFACT_REPO}/${CLOUD_RUN_SERVICE}:latest"
|
||||
|
||||
echo "=== 02: Building and deploying ${CLOUD_RUN_SERVICE} ==="
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
|
||||
# 1. Ensure Artifact Registry repo exists
|
||||
if ! gcloud artifacts repositories describe "${ARTIFACT_REPO}" \
|
||||
--location="${REGION}" --project="${PROJECT_ID}" >/dev/null 2>&1; then
|
||||
gcloud artifacts repositories create "${ARTIFACT_REPO}" \
|
||||
--repository-format=docker \
|
||||
--location="${REGION}" \
|
||||
--project="${PROJECT_ID}" --quiet
|
||||
echo "✓ Artifact Registry repo created: ${ARTIFACT_REPO}"
|
||||
fi
|
||||
|
||||
# 2. Configure Docker auth
|
||||
gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet
|
||||
|
||||
# 3. Build image via Cloud Build (no local Docker required)
|
||||
gcloud builds submit agents/core-logic \
|
||||
--tag="${IMAGE}" \
|
||||
--project="${PROJECT_ID}" \
|
||||
--quiet
|
||||
echo "✓ Image built: ${IMAGE}"
|
||||
|
||||
# 4. Deploy to Cloud Run
|
||||
gcloud run deploy "${CLOUD_RUN_SERVICE}" \
|
||||
--image="${IMAGE}" \
|
||||
--platform=managed \
|
||||
--region="${REGION}" \
|
||||
--service-account="${AGENT_SA}" \
|
||||
--no-allow-unauthenticated \
|
||||
--min-instances=1 \
|
||||
--max-instances=10 \
|
||||
--concurrency=80 \
|
||||
--timeout=300s \
|
||||
--memory=1Gi \
|
||||
--cpu=1 \
|
||||
--set-env-vars="PROJECT_ID=${PROJECT_ID},REGION=${REGION}" \
|
||||
--labels="env=prod,team=osvaucoe,agent=orchestrator" \
|
||||
--quiet
|
||||
|
||||
SERVICE_URL=$(gcloud run services describe "${CLOUD_RUN_SERVICE}" \
|
||||
--region="${REGION}" \
|
||||
--format="value(status.url)")
|
||||
|
||||
echo ""
|
||||
echo "=== 02: Deploy COMPLETE ==="
|
||||
echo " Service URL: ${SERVICE_URL}"
|
||||
echo " REMINDER: Run 03-teardown.sh at end of workday to stop billing."
|
||||
72
infrastructure/03-teardown.sh
Normal file
72
infrastructure/03-teardown.sh
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env bash
|
||||
# 03-teardown.sh — Safely remove all deployed resources
|
||||
# WARNING: Destructive. Requires explicit confirmation.
|
||||
# Source .env before running: source .env
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE}"
|
||||
: "${ARTIFACT_REPO:?Set ARTIFACT_REPO}"
|
||||
: "${AGENT_SA:?Set AGENT_SA}"
|
||||
|
||||
echo "=== 03: TEARDOWN for project ${PROJECT_ID} ==="
|
||||
echo ""
|
||||
echo "WARNING: This will delete Cloud Run services, Artifact Registry images,"
|
||||
echo " and Service Account IAM bindings."
|
||||
echo " GCS buckets and RAG corpora will NOT be deleted (to prevent data loss)."
|
||||
echo ""
|
||||
read -rp "Type 'DELETE' to confirm teardown: " CONFIRM
|
||||
if [[ "${CONFIRM}" != "DELETE" ]]; then
|
||||
echo "Teardown cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
|
||||
# 1. Delete Cloud Run service
|
||||
if gcloud run services describe "${CLOUD_RUN_SERVICE}" \
|
||||
--region="${REGION}" &>/dev/null; then
|
||||
gcloud run services delete "${CLOUD_RUN_SERVICE}" \
|
||||
--region="${REGION}" --quiet
|
||||
echo "✓ Deleted Cloud Run service: ${CLOUD_RUN_SERVICE}"
|
||||
fi
|
||||
|
||||
# 2. Delete Agent Runtime instances (if any)
|
||||
AGENTS=$(gcloud ai agent-engines list \
|
||||
--project="${PROJECT_ID}" --region="${REGION}" \
|
||||
--format="value(name)" 2>/dev/null || echo "")
|
||||
if [ -n "$AGENTS" ]; then
|
||||
while IFS= read -r AGENT_NAME; do
|
||||
gcloud ai agent-engines delete "$AGENT_NAME" \
|
||||
--project="${PROJECT_ID}" --region="${REGION}" --quiet
|
||||
echo "✓ Deleted agent runtime: $AGENT_NAME"
|
||||
done <<< "$AGENTS"
|
||||
fi
|
||||
|
||||
# 3. Delete container images from Artifact Registry
|
||||
gcloud artifacts docker images delete \
|
||||
"${REGION}-docker.pkg.dev/${PROJECT_ID}/${ARTIFACT_REPO}/${CLOUD_RUN_SERVICE}" \
|
||||
--delete-tags --quiet 2>/dev/null || echo " (no images found)"
|
||||
echo "✓ Artifact Registry images cleaned"
|
||||
|
||||
# 4. Remove IAM bindings
|
||||
ROLES=(
|
||||
roles/aiplatform.user
|
||||
roles/run.invoker
|
||||
roles/secretmanager.secretAccessor
|
||||
roles/cloudtrace.agent
|
||||
roles/logging.logWriter
|
||||
roles/monitoring.metricWriter
|
||||
roles/storage.objectAdmin
|
||||
)
|
||||
for ROLE in "${ROLES[@]}"; do
|
||||
gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \
|
||||
--member="serviceAccount:${AGENT_SA}" \
|
||||
--role="${ROLE}" --quiet 2>/dev/null || true
|
||||
done
|
||||
echo "✓ IAM bindings removed"
|
||||
|
||||
echo ""
|
||||
echo "=== 03: Teardown COMPLETE ==="
|
||||
echo "NOTE: GCS buckets and RAG corpora were NOT deleted. Remove manually if needed."
|
||||
78
infrastructure/04-observability-setup.sh
Normal file
78
infrastructure/04-observability-setup.sh
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env bash
|
||||
# 04-observability-setup.sh — Configure Cloud Monitoring, alerting, uptime checks
|
||||
# Idempotent
|
||||
# Source .env before running: source .env
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE}"
|
||||
: "${ALERT_EMAIL:?Set ALERT_EMAIL}"
|
||||
|
||||
echo "=== 04: Setting up observability for ${PROJECT_ID} ==="
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
|
||||
gcloud services enable \
|
||||
monitoring.googleapis.com \
|
||||
logging.googleapis.com \
|
||||
cloudtrace.googleapis.com \
|
||||
--project="${PROJECT_ID}" --quiet
|
||||
echo "✓ Monitoring APIs enabled"
|
||||
|
||||
# 1. Notification channel (email)
|
||||
CHANNEL_FILE=$(gcloud alpha monitoring channels list \
|
||||
--filter="type=email AND labels.email_address=${ALERT_EMAIL}" \
|
||||
--format="value(name)" --project="${PROJECT_ID}" 2>/dev/null | head -1 || true)
|
||||
|
||||
if [[ -z "${CHANNEL_FILE}" ]]; then
|
||||
cat > /tmp/channel.json << EOF
|
||||
{
|
||||
"type": "email",
|
||||
"displayName": "OSVauco Alert Email",
|
||||
"labels": { "email_address": "${ALERT_EMAIL}" }
|
||||
}
|
||||
EOF
|
||||
NOTIFICATION_CHANNEL=$(gcloud alpha monitoring channels create \
|
||||
--channel-content-from-file=/tmp/channel.json \
|
||||
--project="${PROJECT_ID}" \
|
||||
--format="value(name)")
|
||||
echo "✓ Notification channel created: ${NOTIFICATION_CHANNEL}"
|
||||
else
|
||||
NOTIFICATION_CHANNEL="${CHANNEL_FILE}"
|
||||
echo "✓ Notification channel already exists: ${NOTIFICATION_CHANNEL}"
|
||||
fi
|
||||
|
||||
# 2. Create log-based metric for agent errors
|
||||
if ! gcloud logging metrics describe agent-error-count \
|
||||
--project="${PROJECT_ID}" >/dev/null 2>&1; then
|
||||
gcloud logging metrics create agent-error-count \
|
||||
--description="Count of ERROR severity logs from agent" \
|
||||
--log-filter="resource.type=\"cloud_run_revision\" severity=ERROR" \
|
||||
--project="${PROJECT_ID}"
|
||||
echo "✓ Log-based metric 'agent-error-count' created"
|
||||
else
|
||||
echo "✓ Log-based metric already exists"
|
||||
fi
|
||||
|
||||
# 3. Uptime check for Cloud Run service
|
||||
SERVICE_URL=$(gcloud run services describe "${CLOUD_RUN_SERVICE}" \
|
||||
--region="${REGION}" \
|
||||
--format="value(status.url)" 2>/dev/null || echo "")
|
||||
|
||||
if [[ -n "${SERVICE_URL}" ]]; then
|
||||
HOST=$(echo "${SERVICE_URL}" | sed 's|https://||')
|
||||
gcloud monitoring uptime create \
|
||||
--display-name="${CLOUD_RUN_SERVICE}-uptime" \
|
||||
--protocol=HTTPS \
|
||||
--request-path="/health" \
|
||||
--port=443 \
|
||||
--monitored-resource-type=uptime_url \
|
||||
--project="${PROJECT_ID}" \
|
||||
--hostname="${HOST}" 2>/dev/null || true
|
||||
echo "✓ Uptime check configured for ${SERVICE_URL}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== 04: Observability setup COMPLETE ==="
|
||||
echo " Dashboard: https://console.cloud.google.com/monitoring?project=${PROJECT_ID}"
|
||||
68
infrastructure/05-cloudrun-deploy.sh
Normal file
68
infrastructure/05-cloudrun-deploy.sh
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#!/bin/bash
|
||||
# 05-cloudrun-deploy.sh — Deploy ADK agent to Cloud Run using `adk deploy cloud_run`
|
||||
# Run in: local VS Code terminal OR Cloud Shell
|
||||
# Requires: ADK installed (pip install google-adk), gcloud CLI
|
||||
# Source .env before running: source .env
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE}"
|
||||
: "${AGENT_SA:?Set AGENT_SA}"
|
||||
|
||||
APP_NAME="oavauco_root"
|
||||
AGENT_PATH="agents/core-logic"
|
||||
|
||||
echo "=== 05: Cloud Run Deploy via ADK CLI ==="
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
|
||||
gcloud services enable \
|
||||
run.googleapis.com \
|
||||
artifactregistry.googleapis.com \
|
||||
cloudbuild.googleapis.com \
|
||||
--project="${PROJECT_ID}" --quiet
|
||||
|
||||
# Grant compute SA permission to use Cloud Build
|
||||
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")
|
||||
COMPUTE_SA="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
|
||||
|
||||
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
|
||||
--member="serviceAccount:${COMPUTE_SA}" \
|
||||
--role="roles/cloudbuild.builds.builder" --quiet
|
||||
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
|
||||
--member="serviceAccount:${COMPUTE_SA}" \
|
||||
--role="roles/secretmanager.secretAccessor" --quiet
|
||||
echo "✓ IAM bindings for Cloud Build SA applied"
|
||||
|
||||
export GOOGLE_CLOUD_PROJECT="${PROJECT_ID}"
|
||||
export GOOGLE_CLOUD_LOCATION="${REGION}"
|
||||
export GOOGLE_GENAI_USE_VERTEXAI="True"
|
||||
|
||||
# Deploy via ADK CLI
|
||||
# --with_ui includes the ADK dev UI (remove for API-only production deployments)
|
||||
# --no-allow-unauthenticated requires an identity token to call the service
|
||||
echo "Deploying ${CLOUD_RUN_SERVICE} to Cloud Run in ${REGION}..."
|
||||
adk deploy cloud_run \
|
||||
--project="${PROJECT_ID}" \
|
||||
--region="${REGION}" \
|
||||
--service_name="${CLOUD_RUN_SERVICE}" \
|
||||
--app_name="${APP_NAME}" \
|
||||
"${AGENT_PATH}" \
|
||||
-- --no-allow-unauthenticated
|
||||
|
||||
echo ""
|
||||
echo "=== 05: Cloud Run Deploy COMPLETE ==="
|
||||
SERVICE_URL=$(gcloud run services describe "${CLOUD_RUN_SERVICE}" \
|
||||
--region="${REGION}" --project="${PROJECT_ID}" \
|
||||
--format="value(status.url)" 2>/dev/null || echo "(pending)")
|
||||
echo " Service URL: ${SERVICE_URL}"
|
||||
echo ""
|
||||
echo " To call (authenticated):"
|
||||
echo " TOKEN=\$(gcloud auth print-identity-token)"
|
||||
echo " curl -H \"Authorization: Bearer \$TOKEN\" -H 'Content-Type: application/json' \\"
|
||||
echo " -d '{\"message\": \"Hello\"}' ${SERVICE_URL}/run"
|
||||
echo ""
|
||||
echo " COST NOTE: Cloud Run scales to 0. No idle cost."
|
||||
echo " Delete with: gcloud run services delete ${CLOUD_RUN_SERVICE} --region=${REGION} --quiet"
|
||||
80
infrastructure/06-cicd-setup.sh
Normal file
80
infrastructure/06-cicd-setup.sh
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env bash
|
||||
# 06-cicd-setup.sh — Set up Cloud Build trigger + Artifact Registry for CI/CD
|
||||
# Prerequisites: GitHub repo connected to Cloud Build via GCP Console FIRST:
|
||||
# https://console.cloud.google.com/cloud-build/triggers/connect
|
||||
# Source .env before running: source .env
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${GITHUB_OWNER:?Set GITHUB_OWNER}"
|
||||
: "${GITHUB_REPO:?Set GITHUB_REPO}"
|
||||
: "${ARTIFACT_REPO:?Set ARTIFACT_REPO}"
|
||||
: "${CLOUD_RUN_SERVICE:?Set CLOUD_RUN_SERVICE}"
|
||||
|
||||
BRANCH_PATTERN="^main$"
|
||||
|
||||
echo "=== 06: CI/CD Setup for ${PROJECT_ID} ==="
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
|
||||
gcloud services enable \
|
||||
cloudbuild.googleapis.com \
|
||||
artifactregistry.googleapis.com \
|
||||
run.googleapis.com \
|
||||
--project="${PROJECT_ID}" --quiet
|
||||
|
||||
# Create Artifact Registry repo (idempotent)
|
||||
if ! gcloud artifacts repositories describe "${ARTIFACT_REPO}" \
|
||||
--location="${REGION}" --project="${PROJECT_ID}" >/dev/null 2>&1; then
|
||||
gcloud artifacts repositories create "${ARTIFACT_REPO}" \
|
||||
--repository-format=docker \
|
||||
--location="${REGION}" \
|
||||
--project="${PROJECT_ID}" --quiet
|
||||
echo "✓ Artifact Registry repo created: ${ARTIFACT_REPO}"
|
||||
else
|
||||
echo "✓ Artifact Registry repo already exists"
|
||||
fi
|
||||
|
||||
gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet
|
||||
|
||||
# Grant Cloud Build SA permissions
|
||||
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")
|
||||
CB_SA="${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com"
|
||||
|
||||
for ROLE in \
|
||||
roles/run.admin \
|
||||
roles/iam.serviceAccountUser \
|
||||
roles/artifactregistry.writer \
|
||||
roles/secretmanager.secretAccessor; do
|
||||
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
|
||||
--member="serviceAccount:${CB_SA}" --role="${ROLE}" --quiet
|
||||
done
|
||||
echo "✓ Cloud Build SA IAM bindings applied"
|
||||
|
||||
# Create Cloud Build trigger
|
||||
TRIGGER_NAME="${CLOUD_RUN_SERVICE}-main-trigger"
|
||||
EXISTING=$(gcloud builds triggers list \
|
||||
--filter="name=${TRIGGER_NAME}" \
|
||||
--format="value(name)" 2>/dev/null | head -1 || true)
|
||||
|
||||
if [[ -z "${EXISTING}" ]]; then
|
||||
gcloud builds triggers create github \
|
||||
--name="${TRIGGER_NAME}" \
|
||||
--repo-owner="${GITHUB_OWNER}" \
|
||||
--repo-name="${GITHUB_REPO}" \
|
||||
--branch-pattern="${BRANCH_PATTERN}" \
|
||||
--build-config="cloudbuild.yaml" \
|
||||
--project="${PROJECT_ID}" \
|
||||
--quiet
|
||||
echo "✓ Cloud Build trigger created: ${TRIGGER_NAME}"
|
||||
else
|
||||
echo "✓ Trigger already exists: ${TRIGGER_NAME}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== 06: CI/CD Setup COMPLETE ==="
|
||||
echo " NOTE: GitHub connection must be pre-authorized at:"
|
||||
echo " https://console.cloud.google.com/cloud-build/triggers/connect?project=${PROJECT_ID}"
|
||||
echo " After first deploy, switch traffic manually:"
|
||||
echo " gcloud run services update-traffic ${CLOUD_RUN_SERVICE} --to-latest --region=${REGION}"
|
||||
91
infrastructure/07-rag-setup.sh
Normal file
91
infrastructure/07-rag-setup.sh
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env bash
|
||||
# 07-rag-setup.sh — Create Vertex AI RAG Engine corpus and upload initial documents
|
||||
# Idempotent
|
||||
# Source: Vertex AI RAG Engine SDK (google-cloud-aiplatform >= 1.87)
|
||||
# NOTE: RAG Engine in us-central1 requires allowlist access.
|
||||
# Contact: vertex-ai-rag-engine-support@google.com
|
||||
# Alternative: set REGION=us-east1 or us-east4 for immediate access.
|
||||
# Source .env before running: source .env
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${RAG_CORPUS_DISPLAY_NAME:?Set RAG_CORPUS_DISPLAY_NAME}"
|
||||
|
||||
echo "=== 07: Setting up Vertex AI RAG Engine ==="
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
gcloud services enable aiplatform.googleapis.com --quiet
|
||||
|
||||
# Create GCS bucket for corpus source documents (idempotent)
|
||||
CORPUS_BUCKET="${PROJECT_ID}-agent-corpus"
|
||||
if ! gsutil ls -b "gs://${CORPUS_BUCKET}" &>/dev/null; then
|
||||
gsutil mb -l "${REGION}" -b on "gs://${CORPUS_BUCKET}"
|
||||
echo "✓ GCS corpus bucket created: gs://${CORPUS_BUCKET}"
|
||||
else
|
||||
echo "✓ GCS corpus bucket exists: gs://${CORPUS_BUCKET}"
|
||||
fi
|
||||
|
||||
# Upload seed documents if present
|
||||
if [[ -d "docs/corpus-seed" ]]; then
|
||||
gsutil -m cp docs/corpus-seed/*.md "gs://${CORPUS_BUCKET}/seed/" 2>/dev/null || true
|
||||
echo "✓ Seed documents uploaded to gs://${CORPUS_BUCKET}/seed/"
|
||||
fi
|
||||
|
||||
# Run Python to create/update corpus
|
||||
python3 - << PYEOF
|
||||
import os, sys
|
||||
try:
|
||||
import vertexai
|
||||
from vertexai.preview import rag
|
||||
except ImportError:
|
||||
print("ERROR: google-cloud-aiplatform not installed. Run: pip install google-cloud-aiplatform>=1.87.0")
|
||||
sys.exit(1)
|
||||
|
||||
PROJECT_ID = os.environ["PROJECT_ID"]
|
||||
REGION = os.environ["REGION"]
|
||||
CORPUS_DISPLAY_NAME = os.environ["RAG_CORPUS_DISPLAY_NAME"]
|
||||
CORPUS_BUCKET = f"{PROJECT_ID}-agent-corpus"
|
||||
|
||||
vertexai.init(project=PROJECT_ID, location=REGION)
|
||||
|
||||
corpus = None
|
||||
for c in rag.list_corpora():
|
||||
if c.display_name == CORPUS_DISPLAY_NAME:
|
||||
corpus = c
|
||||
print(f"✓ RAG corpus already exists: {c.name}")
|
||||
break
|
||||
|
||||
if corpus is None:
|
||||
embedding_config = rag.EmbeddingModelConfig(
|
||||
publisher_model="publishers/google/models/text-embedding-005"
|
||||
)
|
||||
corpus = rag.create_corpus(
|
||||
display_name=CORPUS_DISPLAY_NAME,
|
||||
embedding_model_config=embedding_config,
|
||||
)
|
||||
print(f"✓ RAG corpus created: {corpus.name}")
|
||||
|
||||
gcs_uri = f"gs://{CORPUS_BUCKET}/seed/"
|
||||
try:
|
||||
rag.import_files(
|
||||
corpus_name=corpus.name,
|
||||
paths=[gcs_uri],
|
||||
chunk_size=512,
|
||||
chunk_overlap=50,
|
||||
max_embedding_requests_per_min=900,
|
||||
)
|
||||
print(f"✓ Documents imported from {gcs_uri}")
|
||||
except Exception as e:
|
||||
print(f" WARNING: Document import skipped or failed: {e}")
|
||||
print(" Import manually via: https://console.cloud.google.com/vertex-ai/rag")
|
||||
|
||||
with open("/tmp/rag_corpus_name.txt", "w") as f:
|
||||
f.write(corpus.name)
|
||||
print(f"\n Corpus resource name: {corpus.name}")
|
||||
print(f" Add to .env: RAG_CORPUS_NAME={corpus.name}")
|
||||
PYEOF
|
||||
|
||||
echo ""
|
||||
echo "=== 07: RAG Engine setup COMPLETE ==="
|
||||
echo " View corpus: https://console.cloud.google.com/vertex-ai/rag?project=${PROJECT_ID}"
|
||||
76
infrastructure/08-memorybank-setup.sh
Normal file
76
infrastructure/08-memorybank-setup.sh
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#!/usr/bin/env bash
|
||||
# 08-memorybank-setup.sh — Create Vertex AI Agent Platform Memory Bank instance
|
||||
# Idempotent
|
||||
# Requires: google-cloud-aiplatform >= 1.111.0
|
||||
# UNKNOWN: gcloud CLI equivalent for client.agent_engines.create() — SDK-only (OQ-01)
|
||||
# Source .env before running: source .env
|
||||
set -euo pipefail
|
||||
|
||||
: "${PROJECT_ID:?Set PROJECT_ID}"
|
||||
: "${REGION:?Set REGION}"
|
||||
: "${AGENT_SA:?Set AGENT_SA}"
|
||||
|
||||
MEMORY_INSTANCE_DISPLAY_NAME="${MEMORY_INSTANCE_DISPLAY_NAME:-${PROJECT_ID}-memory-bank}"
|
||||
|
||||
echo "=== 08: Setting up Vertex AI Memory Bank ==="
|
||||
|
||||
bash "$(dirname "$0")/00-authcheck.sh"
|
||||
gcloud services enable aiplatform.googleapis.com --quiet
|
||||
|
||||
# Run Python to create/update Agent Engine instance with Memory Bank
|
||||
python3 - << PYEOF
|
||||
import os, sys
|
||||
try:
|
||||
import vertexai
|
||||
from vertexai.preview import agent_engines
|
||||
except ImportError:
|
||||
print("ERROR: google-cloud-aiplatform >= 1.111.0 required.")
|
||||
print(" Run: pip install 'google-cloud-aiplatform>=1.111.0'")
|
||||
sys.exit(1)
|
||||
|
||||
PROJECT_ID = os.environ["PROJECT_ID"]
|
||||
REGION = os.environ["REGION"]
|
||||
DISPLAY_NAME = os.environ.get("MEMORY_INSTANCE_DISPLAY_NAME", f"{PROJECT_ID}-memory-bank")
|
||||
|
||||
vertexai.init(project=PROJECT_ID, location=REGION)
|
||||
client = vertexai.Client(project=PROJECT_ID, location=REGION)
|
||||
|
||||
existing = list(client.agent_engines.list())
|
||||
instance = None
|
||||
for eng in existing:
|
||||
if hasattr(eng, "display_name") and eng.display_name == DISPLAY_NAME:
|
||||
instance = eng
|
||||
print(f"✓ Memory Bank instance already exists: {eng.api_resource.name}")
|
||||
break
|
||||
|
||||
if instance is None:
|
||||
memory_bank_config = {
|
||||
"memories_ttl_days": 30,
|
||||
"generate_memory_config": {
|
||||
"trigger_config": {"trigger_type": "ON_SESSION_END"}
|
||||
},
|
||||
"similarity_search_config": {"top_k": 5}
|
||||
}
|
||||
instance = client.agent_engines.create(
|
||||
display_name=DISPLAY_NAME,
|
||||
spec={"context_spec": {"memory_bank_config": memory_bank_config}}
|
||||
)
|
||||
print(f"✓ Memory Bank instance created: {instance.api_resource.name}")
|
||||
|
||||
instance_name = instance.api_resource.name
|
||||
with open("/tmp/memory_bank_instance.txt", "w") as f:
|
||||
f.write(instance_name)
|
||||
print(f"\n Instance resource name: {instance_name}")
|
||||
print(f" Add to .env: MEMORY_BANK_INSTANCE={instance_name}")
|
||||
PYEOF
|
||||
|
||||
# Grant agent SA memory permissions
|
||||
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
|
||||
--member="serviceAccount:${AGENT_SA}" \
|
||||
--role="roles/aiplatform.user" \
|
||||
--quiet 2>/dev/null || true
|
||||
echo "✓ roles/aiplatform.user granted to ${AGENT_SA}"
|
||||
|
||||
echo ""
|
||||
echo "=== 08: Memory Bank setup COMPLETE ==="
|
||||
echo " View instances: https://console.cloud.google.com/vertex-ai/agents?project=${PROJECT_ID}"
|
||||
Loading…
Reference in New Issue
Block a user