CLI Workflows

This page contains practical examples of common CLI workflows for managing Teenode resources. These examples can be adapted and combined for your specific needs.

Basic Setup Workflow

Complete setup from authentication to first deployment:

#!/bin/bash
# setup-new-account.sh

# 1. Authenticate
echo "Logging in..."
teenode auth login

# 2. Create team
read -p "Team name: " TEAM_NAME
teenode team create --name "$TEAM_NAME"

# 3. Create SSH key
KEY_NAME="$(whoami)-$(hostname)"
echo "Creating SSH key: $KEY_NAME"
ssh-keygen -t ed25519 -f ~/.ssh/$KEY_NAME -N ""
teenode ssh-key add --name "$KEY_NAME" --key-file ~/.ssh/$KEY_NAME.pub

# 4. Create first VM
read -p "VM name: " VM_NAME
teenode vm create \
  --name "$VM_NAME" \
  --region us-east \
  --cpu 2 \
  --memory 4096 \
  --ssh-key "$KEY_NAME"

# 5. Get VM IP
sleep 10
VM_IP=$(teenode vm describe "$VM_NAME" | grep "IP Address" | awk '{print $NF}')
echo "VM ready at: $VM_IP"

# 6. Connect and verify
echo "Verifying connection..."
ssh -i ~/.ssh/$KEY_NAME root@$VM_IP "uname -a"

echo "✓ Setup complete!"

Batch VM Creation

Create multiple VMs for a cluster:

#!/bin/bash
# create-cluster.sh

CLUSTER_NAME="web-cluster"
NODE_COUNT=3
REGION="us-east"
CPU=4
MEMORY=8192

echo "Creating $CLUSTER_NAME with $NODE_COUNT nodes..."

for i in $(seq 1 $NODE_COUNT); do
  VM_NAME="$CLUSTER_NAME-node-$i"
  echo "Creating $VM_NAME..."

  teenode vm create \
    --name "$VM_NAME" \
    --region "$REGION" \
    --cpu "$CPU" \
    --memory "$MEMORY" \
    --tags "cluster=$CLUSTER_NAME,role=worker" \
    --wait

  # Mark creation time
  echo "✓ $VM_NAME created"
done

echo "✓ Cluster $CLUSTER_NAME created with $NODE_COUNT nodes"

# List all cluster VMs
echo "Cluster VMs:"
teenode vm list --tags "cluster=$CLUSTER_NAME"

Multi-Project Monitoring

Monitor status across multiple projects:

#!/bin/bash
# monitor-all-projects.sh

echo "Project Status Report - $(date)"
echo "================================"

# Get all projects
PROJECTS=$(teenode project list -o json | jq -r '.[].name')

for project in $PROJECTS; do
  echo ""
  echo "Project: $project"

  # Get project status
  teenode project info "$project" -o json | jq '{
    status: .status,
    deployments: .deployment_count,
    created: .created_at,
    updated: .updated_at
  }'

  # Get latest deployment
  LATEST=$(teenode deployment list "$project" --limit 1 -o json | jq -r '.[0]')

  if [ "$LATEST" != "null" ]; then
    echo "  Latest deployment:"
    echo "$LATEST" | jq '{
      id: .id,
      status: .status,
      created: .created_at
    }' | sed 's/^/    /'
  fi
done

echo ""
echo "✓ Report complete"

Automated Backup Workflow

Regular snapshots with automatic cleanup:

#!/bin/bash
# backup-vm.sh - Run with cron for automation

VM_NAME="$1"
RETENTION_DAYS=7

if [ -z "$VM_NAME" ]; then
  echo "Usage: $0 <vm-name>"
  exit 1
fi

SNAPSHOT_NAME="$VM_NAME-backup-$(date +%Y%m%d-%H%M%S)"

echo "Creating snapshot: \$SNAPSHOT_NAME"
teenode vm snapshot create "$VM_NAME" --name "\$SNAPSHOT_NAME"

if [ $? -ne 0 ]; then
  echo "✗ Snapshot creation failed"
  exit 1
fi

echo "✓ Snapshot created"

# Clean up old snapshots (older than RETENTION_DAYS)
echo "Cleaning up old snapshots..."

CUTOFF_DATE=$(date -d "$RETENTION_DAYS days ago" +%s)

teenode vm snapshot list "$VM_NAME" -o json | \
  jq -r ".[] | select(.created_at < $CUTOFF_DATE) | .name" | \
  while read -r old_snapshot; do
    echo "  Deleting $old_snapshot"
    teenode vm snapshot delete "$VM_NAME" "$old_snapshot"
  done

echo "✓ Backup workflow complete"

# Add to crontab:
# 0 2 * * * /usr/local/bin/backup-vm.sh my-vm 2>&1 | logger

Environment Synchronization

Keep environment variables in sync across environments:

#!/bin/bash
# sync-env.sh

SOURCE_PROJECT="$1"
TARGET_PROJECTS="${@:2}"

if [ -z "$SOURCE_PROJECT" ] || [ -z "$TARGET_PROJECTS" ]; then
  echo "Usage: $0 <source-project> <target-project> [target-project...]"
  exit 1
fi

echo "Syncing environment from $SOURCE_PROJECT to $TARGET_PROJECTS"

# Get environment from source
SOURCE_ENV=$(teenode env list "$SOURCE_PROJECT" -o json)

echo "$SOURCE_ENV" | jq -r 'to_entries[] | "(.key)=(.value)"' | \
  while read -r var; do
    KEY=$(echo "$var" | cut -d= -f1)
    VALUE=$(echo "$var" | cut -d= -f2-)

    for project in $TARGET_PROJECTS; do
      echo "Setting $KEY in $project"
      teenode env set "$project" "$KEY=$VALUE"
    done
  done

echo "✓ Environment synchronized"

# Verify
echo ""
echo "Verification:"
for project in $SOURCE_PROJECT $TARGET_PROJECTS; do
  echo "$project:"
  teenode env list "$project" | head -5
done

Deployment Automation

Auto-deploy with health checks:

#!/bin/bash
# auto-deploy.sh

PROJECT_NAME="$1"
BRANCH="${2:-main}"
HEALTH_CHECK_URL="${3:-http://localhost/health}"

if [ -z "$PROJECT_NAME" ]; then
  echo "Usage: $0 <project-name> [branch] [health-check-url]"
  exit 1
fi

echo "Deploying $PROJECT_NAME from $BRANCH..."

# Trigger deployment
DEPLOYMENT=$(teenode deployment create "$PROJECT_NAME" --branch "$BRANCH" -o json)
DEPLOYMENT_ID=$(echo "$DEPLOYMENT" | jq -r '.id')

echo "Deployment ID: $DEPLOYMENT_ID"

# Wait for deployment to start
sleep 5

# Monitor deployment progress
MAX_ATTEMPTS=180
ATTEMPT=0

while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do
  STATUS=$(teenode deployment describe "$DEPLOYMENT_ID" -o json | jq -r '.status')

  echo "Status: $STATUS"

  case $STATUS in
    BUILDING)
      echo "  Building application..."
      ;;
    DEPLOYING)
      echo "  Deploying to infrastructure..."
      ;;
    RUNNING)
      echo "  ✓ Deployment completed"
      break
      ;;
    FAILED)
      echo "  ✗ Deployment failed"
      teenode deployment logs "$DEPLOYMENT_ID"
      exit 1
      ;;
  esac

  sleep 10
  ((ATTEMPT++))
done

# Health check
echo "Performing health check..."
sleep 5

HEALTH=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_CHECK_URL")

if [ "$HEALTH" = "200" ]; then
  echo "✓ Application is healthy"
else
  echo "✗ Health check failed (HTTP $HEALTH)"
  exit 1
fi

echo "✓ Deployment complete and verified"

Cost Analysis Workflow

Analyze and report on resource usage:

#!/bin/bash
# cost-analysis.sh

echo "Resource Usage and Cost Analysis"
echo "=================================="

# Get all VMs
TOTAL_COST=0
TOTAL_CPU=0
TOTAL_MEMORY=0

echo ""
echo "Virtual Machines:"
echo "Name                  | CPU | Memory | Monthly Cost"
echo "---------------------------------------------------"

teenode vm list -o json | jq -r '.[] | \
  "\(.name),\(.cpu),\(.memory)"' | \
  while IFS=',' read -r name cpu memory; do
    # Estimate cost (example pricing)
    CPU_COST=$(echo "$cpu * 0.10" | bc)  # $0.10 per CPU per day
    MEMORY_COST=$(echo "$memory / 1024 * 0.05" | bc)  # $0.05 per GB per day
    DAILY_COST=$(echo "$CPU_COST + $MEMORY_COST" | bc)
    MONTHLY_COST=$(echo "$DAILY_COST * 30" | bc)

    printf "%-20s | %3s | %5dM | $%8.2f
" "$name" "$cpu" "$memory" "$MONTHLY_COST"

    TOTAL_COST=$(echo "$TOTAL_COST + $MONTHLY_COST" | bc)
  done

# Get all projects and deployments
echo ""
echo "Deployments:"
echo "Project              | Deployments | Storage"
echo "---------------------------------------------------"

teenode project list -o json | jq -r '.[] | .name' | \
  while read -r project; do
    COUNT=$(teenode deployment list "$project" -o json | jq 'length')
    STORAGE=$(teenode project info "$project" -o json | jq -r '.storage // 0')

    # Storage cost
    STORAGE_COST=$(echo "$STORAGE * 0.03 * 30" | bc)
    TOTAL_COST=$(echo "$TOTAL_COST + $STORAGE_COST" | bc)

    printf "%-20s | %11d | %6dGB
" "$project" "$COUNT" "$STORAGE"
  done

echo ""
echo "---------------------------------------------------"
echo "Estimated Monthly Cost: $$(echo "scale=2; $TOTAL_COST" | bc)"
echo "✓ Cost analysis complete"

Disaster Recovery Workflow

Complete DR procedure with snapshots:

#!/bin/bash
# disaster-recovery.sh

SOURCE_VM="$1"
TARGET_VM="$2-recovered-$(date +%s)"

if [ -z "\$SOURCE_VM" ] || [ -z "\$TARGET_VM" ]; then
  echo "Usage: $0 <source-vm> <prefix>"
  echo "Example: $0 prod-db db"
  exit 1
fi

echo "Starting disaster recovery..."
echo "Source: \$SOURCE_VM"
echo "Target: \$TARGET_VM"

# Create snapshot if not restoring from existing
read -p "Restore from snapshot? (y/n) " RESTORE

if [ "$RESTORE" = "y" ]; then
  echo "Available snapshots:"
  teenode vm snapshot list "\$SOURCE_VM" | nl

  read -p "Snapshot number: " SNAPSHOT_NUM

  SNAPSHOT=$(teenode vm snapshot list "\$SOURCE_VM" | sed -n "\$SNAPSHOT_NUM p" | awk '{print $1}')
  echo "Using snapshot: \$SNAPSHOT"
else
  echo "Creating fresh snapshot..."
  SNAPSHOT="\$SOURCE_VM-recovery-$(date +%Y%m%d-%H%M%S)"
  teenode vm snapshot create "\$SOURCE_VM" --name "\$SNAPSHOT"
fi

# Create new VM from snapshot
echo "Creating new VM from snapshot..."
teenode vm create-from-snapshot \
  --name "\$TARGET_VM" \
  --snapshot "\$SNAPSHOT" \
  --region us-east \
  --wait

echo "✓ New VM created: \$TARGET_VM"

# Verify data integrity
echo "Verifying data integrity..."
TARGET_IP=$(teenode vm describe "\$TARGET_VM" | grep "IP Address" | awk '{print $NF}')
ssh -i ~/.ssh/id_ed25519 root@$TARGET_IP "\
  echo 'Checking filesystems...' && \
  df -h && \
  echo 'Checking services...' && \
  systemctl status"

echo "✓ Disaster recovery complete"
echo "New VM: \$TARGET_VM ($TARGET_IP)"

# Optional: Delete source
read -p "Delete source VM? (y/n) " DELETE
if [ "$DELETE" = "y" ]; then
  teenode vm delete "\$SOURCE_VM"
  echo "✓ Source VM deleted"
fi

Audit and Compliance Workflow

Generate compliance audit trail:

#!/bin/bash
# compliance-audit.sh

REPORT_DATE=$(date +%Y-%m-%d)
REPORT_FILE="compliance-audit-$REPORT_DATE.json"

echo "Generating compliance audit report..."

# Initialize report
cat > "$REPORT_FILE" << 'EOF'
{
  "report_date": "'"$REPORT_DATE"'",
  "timestamp": "'"$(date -Iseconds)"'",
  "vms": [],
  "projects": [],
  "security_findings": []
}
EOF

# Check all VMs for security settings
echo "Checking VM security settings..."

teenode vm list -o json | jq -r '.[] | .name' | \
  while read -r vm; do
    # Get attestation
    ATTESTATION=$(teenode vm attest "$vm" --output /dev/stdout 2>/dev/null)
    DEBUG=$(echo "$ATTESTATION" | jq '.report.policy.debug_allowed')

    # Create VM report
    VM_REPORT=$(jq -n \
      --arg name "$vm" \
      --argjson debug "$DEBUG" \
      '{
        name: $name,
        debug_allowed: $debug,
        checked_at: "'$(date -Iseconds)'"
      }')

    jq ".vms += [$VM_REPORT]" "$REPORT_FILE" > "$REPORT_FILE.tmp"
    mv "$REPORT_FILE.tmp" "$REPORT_FILE"

    if [ "$DEBUG" = "true" ]; then
      FINDING=$(jq -n --arg vm "$vm" \
        '{
          severity: "high",
          finding: "Debug mode enabled",
          vm: $vm,
          recommendation: "Disable debug mode for production"
        }')

      jq ".security_findings += [$FINDING]" "$REPORT_FILE" > "$REPORT_FILE.tmp"
      mv "$REPORT_FILE.tmp" "$REPORT_FILE"
    fi
  done

# Check project configurations
echo "Checking project configurations..."

teenode project list -o json | jq '.[] | .' | \
  while read -r project; do
    PROJECT_NAME=$(echo "$project" | jq -r '.name')

    PROJECT_REPORT=$(echo "$project" | jq '{
      name: .name,
      auto_deploy: .auto_deploy_enabled,
      created_at: .created_at
    }')

    jq ".projects += [$PROJECT_REPORT]" "$REPORT_FILE" > "$REPORT_FILE.tmp"
    mv "$REPORT_FILE.tmp" "$REPORT_FILE"
  done

echo "✓ Report generated: $REPORT_FILE"

# Display summary
echo ""
echo "Audit Summary:"
jq '{
  total_vms: (.vms | length),
  total_projects: (.projects | length),
  security_findings: (.security_findings | length),
  debug_enabled_vms: [.vms[] | select(.debug_allowed == true) | .name]
}' "$REPORT_FILE"

CI/CD Integration Workflow

Automated deployment from Git push:

#!/bin/bash
# ci-cd-webhook-handler.sh
# Handle webhook from GitHub/GitLab for auto-deployment

# Parse webhook payload
PUSH_EVENT=$(echo "$1" | jq '.push_event')
BRANCH=$(echo "$PUSH_EVENT" | jq -r '.ref' | sed 's|refs/heads/||')
COMMIT=$(echo "$PUSH_EVENT" | jq -r '.after')
PROJECT=$(echo "$PUSH_EVENT" | jq -r '.repository.name')

if [ "$BRANCH" != "main" ]; then
  echo "Not main branch, skipping deployment"
  exit 0
fi

echo "Webhook received for $PROJECT:$BRANCH"
echo "Commit: $COMMIT"

# Verify commit is signed (optional)
# git verify-commit $COMMIT || exit 1

# Build artifact
echo "Building..."
docker build -t $PROJECT:$COMMIT .

if [ $? -ne 0 ]; then
  echo "Build failed"
  exit 1
fi

# Push to registry
docker push $PROJECT:$COMMIT

# Deploy to Teenode
echo "Deploying..."
teenode deployment create "$PROJECT" \
  --branch "$BRANCH" \
  --image "$PROJECT:$COMMIT"

# Wait for deployment
sleep 30
DEPLOYMENT_ID=$(teenode deployment list "$PROJECT" --limit 1 | head -1)

# Verify health
HEALTH=$(curl -s -o /dev/null -w "%{http_code}" "https://$PROJECT.teenode.app/health")

if [ "$HEALTH" = "200" ]; then
  echo "✓ Deployment successful"
else
  echo "✗ Deployment failed health check"
  exit 1
fi

Fleet Management Workflow

Manage multiple VMs as a fleet:

#!/bin/bash
# fleet-manager.sh

FLEET_NAME="$1"
COMMAND="$2"

if [ -z "$FLEET_NAME" ] || [ -z "$COMMAND" ]; then
  echo "Usage: $0 <fleet-name> <command>"
  echo "Commands: status, restart, update, scale"
  exit 1
fi

# Get all VMs in fleet
VMS=$(teenode vm list --tags "fleet=$FLEET_NAME" -o json | jq -r '.[].name')

case $COMMAND in
  status)
    echo "Fleet: $FLEET_NAME"
    for vm in $VMS; do
      STATUS=$(teenode vm describe "$vm" | grep "Status:" | awk '{print $NF}')
      echo "  $vm: $STATUS"
    done
    ;;

  restart)
    echo "Restarting fleet: $FLEET_NAME"
    for vm in $VMS; do
      echo "  Restarting $vm..."
      teenode vm stop "$vm" --wait
      teenode vm start "$vm" --wait
    done
    echo "✓ Fleet restarted"
    ;;

  update)
    echo "Updating fleet: $FLEET_NAME"
    for vm in $VMS; do
      echo "  Updating $vm..."
      ssh root@$(teenode vm describe "$vm" | grep "IP Address" | awk '{print $NF}') \
        "apt update && apt upgrade -y"
    done
    echo "✓ Fleet updated"
    ;;

  scale)
    read -p "Scale to how many nodes? " COUNT
    CURRENT=$(echo "$VMS" | wc -l)

    if [ $COUNT -gt $CURRENT ]; then
      echo "Adding $((COUNT - CURRENT)) nodes..."
      for i in $(seq $((CURRENT + 1)) $COUNT); do
        teenode vm create \
          --name "$FLEET_NAME-node-$i" \
          --tags "fleet=$FLEET_NAME"
      done
    elif [ $COUNT -lt $CURRENT ]; then
      echo "Removing $((CURRENT - COUNT)) nodes..."
      echo "$VMS" | tail -n $((CURRENT - COUNT)) | \
        while read -r vm; do
          teenode vm delete "$vm"
        done
    fi
    ;;

  *)
    echo "Unknown command: $COMMAND"
    exit 1
    ;;
esac

Tips for Production Scripts

  • Always use error checking (set -e or check exit codes)
  • Log operations with timestamps for auditing
  • Include rollback procedures for failed deployments
  • Use retry logic for transient failures
  • Set appropriate timeouts for long operations
  • Test scripts in staging before running in production
  • Store scripts in version control
  • Use systemd or cron for scheduled tasks

Next Steps

These workflows can be customized and combined for your specific use cases. Start with simpler workflows and gradually automate more complex processes.