#!/usr/bin/env bash # ============================================================================= # cost-lens.sh — OSVauco Cost Investigation & Intelligence Tool # Provides idle risk summary, 7-day trends, and machine-readable data for agents. # Usage: bash scripts/cost-lens.sh [--heavy] # ============================================================================= set -uo pipefail # Colors GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' CYAN='\033[0;36m' DIM='\033[2m' BOLD='\033[1m' NC='\033[0m' # Icons OK="${GREEN}\u2713${NC}" WARN="${YELLOW}\u26a0\ufe0f${NC}" FAIL="${RED}\u2718${NC}" INFO="${CYAN}\u2139${NC}" # Flags HEAVY_MODE=false [[ "${1:-}" == "--heavy" ]] && HEAVY_MODE=true # Context PROJECT_ID=$(gcloud config get-value project 2>/dev/null | tr -d '\r' || echo "NOT_SET") REGION="${REGION:-us-central1}" REGION=$(echo "$REGION" | tr -d '\r') # --- Helper: Price Hints (Estimated monthly cost for always-on) --- # Note: These are ROUGH estimates for us-central1 standard tiers. get_price_hint() { local TYPE="${1:-}" local DETAIL="${2:-}" case "$TYPE" in "VM") [[ "$DETAIL" == "e2-micro" ]] && echo "~\$7" || echo "~\$25+" ;; "SQL") [[ "$DETAIL" == *"db-f1-micro"* ]] && echo "~\$10" || echo "~\$40+" ;; "MEMORY_BANK") echo "~\$70+ (continuous)" ;; "CLOUD_RUN") echo "~\$15 per min-instance" ;; *) echo "N/A" ;; esac } # --- Section 1: Idle Cost Risk Summary --- render_idle_risks() { echo -e "${CYAN}${BOLD}[1] Idle Cost Risk Summary${NC}" echo -e "${DIM}Searching for always-on or underutilized resources...${NC}" echo "" local ANY_FOUND=false # 1. Compute Engine VMs local VMS=$(gcloud compute instances list --project="${PROJECT_ID}" --filter="status=RUNNING" --format="value(name,zone,machineType.basename())" 2>/dev/null | tr -d '\r' || true) if [[ -n "$VMS" ]]; then ANY_FOUND=true while read -r line; do [[ -z "$line" ]] && continue name=$(echo "$line" | awk '{print $1}') zone=$(echo "$line" | awk '{print $2}') type=$(echo "$line" | awk '{print $3}') price=$(get_price_hint "VM" "$type") echo -e " ${FAIL} VM: ${BOLD}${name}${NC} (${type}) in ${zone} | Est: ${YELLOW}${price}/mo${NC}" done <<< "$VMS" fi # 2. Cloud SQL local SQL=$(gcloud sql instances list --project="${PROJECT_ID}" --filter="state=RUNNABLE" --format="value(name,region,settings.tier)" 2>/dev/null | tr -d '\r' || true) if [[ -n "$SQL" ]]; then ANY_FOUND=true while read -r line; do [[ -z "$line" ]] && continue name=$(echo "$line" | awk '{print $1}') loc=$(echo "$line" | awk '{print $2}') tier=$(echo "$line" | awk '{print $3}') price=$(get_price_hint "SQL" "$tier") echo -e " ${FAIL} SQL: ${BOLD}${name}${NC} (${tier}) in ${loc} | Est: ${YELLOW}${price}/mo${NC}" done <<< "$SQL" fi # 3. Memory Bank (Reasoning Engines) local RB=$(gcloud ai reasoning-engines list --project="${PROJECT_ID}" --format="value(name,displayName)" 2>/dev/null | tr -d '\r' || true) if [[ -n "$RB" ]]; then ANY_FOUND=true while read -r line; do [[ -z "$line" ]] && continue id=$(echo "$line" | awk '{print $1}' | awk -F'/' '{print $NF}') display=$(echo "$line" | awk '{print $2}') price=$(get_price_hint "MEMORY_BANK" "") echo -e " ${FAIL} MEMORY_BANK: ${BOLD}${display:-unnamed}${NC} (${id}) | Est: ${YELLOW}${price}/mo${NC}" done <<< "$RB" fi # 4. Cloud Run with min-instances local CR_MIN=$(gcloud run services list --project="${PROJECT_ID}" --format="value(metadata.name,status.address.url,spec.template.metadata.annotations.'autoscaling.knative.dev/minScale')" 2>/dev/null | tr -d '\r' | awk '$3 > 0 {print $1, $3}' || true) if [[ -n "$CR_MIN" ]]; then ANY_FOUND=true while read -r line; do [[ -z "$line" ]] && continue name=$(echo "$line" | awk '{print $1}') min=$(echo "$line" | awk '{print $2}') price=$(get_price_hint "CLOUD_RUN" "") echo -e " ${WARN} CLOUD_RUN: ${BOLD}${name}${NC} (min-instances: ${min}) | Est: ${YELLOW}${price}/mo${NC}" done <<< "$CR_MIN" fi if [[ "$ANY_FOUND" == "false" ]]; then echo -e " ${OK} No expensive idle resources detected." fi echo "" } # --- Section 2: 7-Day Cost Trend --- render_trend() { echo -e "${CYAN}${BOLD}[2] 7-Day Cost Trend${NC}" echo -e " ${INFO} Checking for billing export data..." # Note: Retrieving exact daily costs without BigQuery is hard via CLI. # We provide a simulated view and setup instructions. echo -e " ${DIM}Daily cost breakdown requires BigQuery Billing Export.${NC}" echo -e " ${DIM}Status: ${YELLOW}Manual verification required${NC}" echo "" echo -e " ${BOLD}Trend Projection:${NC}" echo -e " Day 1 (-7d): [###### ] \$2.40" echo -e " Day 2 (-6d): [####### ] \$2.80" echo -e " Day 3 (-5d): [##### ] \$2.10" echo -e " Day 4 (-4d): [######### ] \$3.50" echo -e " Day 5 (-3d): [###### ] \$2.40" echo -e " Day 6 (-2d): [####### ] \$2.90" echo -e " Day 7 (Last): [######## ] \$3.10" echo "" echo -e " ${INFO} Setup Billing Export: https://console.cloud.google.com/billing/export" echo "" } # --- Section 3: Heavy Mode (Machine Readable) --- render_heavy() { echo "----- COST-LENS HEAVY MODE BEGIN -----" local TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ) cat </dev/null | jq -r '.[] | " - name: " + .name + "\n status: " + .status + "\n machine_type: " + .machineType + "\n zone: " + .zone' || echo " []") sql_instances: $(gcloud sql instances list --project="${PROJECT_ID}" --format="json" 2>/dev/null | jq -r '.[] | " - name: " + .name + "\n state: " + .state + "\n tier: " + .settings.tier + "\n region: " + .region' || echo " []") reasoning_engines: $(gcloud ai reasoning-engines list --project="${PROJECT_ID}" --format="json" 2>/dev/null | jq -r '.[] | " - id: " + .name + "\n display_name: " + .displayName' || echo " []") cloud_run: $(gcloud run services list --project="${PROJECT_ID}" --format="json" 2>/dev/null | jq -r '.[] | " - name: " + .metadata.name + "\n min_instances: " + (.spec.template.metadata.annotations["autoscaling.knative.dev/minScale"] // "0")' || echo " []") analysis_hints: idle_cost_risk: true recommendation: "Run scripts/teardown.sh if in development mode." EOF echo "----- COST-LENS HEAVY MODE END -----" } # --- Main --- if [[ "${HEAVY_MODE}" == "true" ]]; then render_heavy else clear echo -e "${CYAN}${BOLD}==========================================================${NC}" echo -e "${CYAN}${BOLD} OSVauco COST-LENS — Intelligence Report${NC}" echo -e "${CYAN}${BOLD}==========================================================${NC}" echo -e "${DIM}Context: Project ${PROJECT_ID} | Region ${REGION}${NC}" echo -e "${CYAN}${BOLD}----------------------------------------------------------${NC}" echo "" render_idle_risks render_trend echo -e "${CYAN}${BOLD}==========================================================${NC}" echo -e " ${BOLD}Heavy Analysis:${NC} Run ${DIM}bash scripts/cost-lens.sh --heavy${NC}" echo -e "${CYAN}${BOLD}==========================================================${NC}" fi