# Automatización con CLI

{% hint style="success" %}
**Requisitos previos:** Instala el SDK (`pip install clore-ai`) y configura tu clave de API. Consulta el [Inicio rápido de Python](/guides/guides_v2-es/primeros-pasos/python-quickstart.md) si aún no lo has hecho.
{% endhint %}

## Flujo de trabajo básico

El bucle principal: **buscar → desplegar → conectar → cancelar**.

```bash
# 1. Encuentra una GPU
clore search --gpu "RTX 4090" --max-price 2.0 --sort price --limit 5

# 2. Desplegar (usa una ID de servidor del paso 1)
clore deploy 142 \
  --image cloreai/ubuntu22.04-cuda12 \
  --type on-demand \
  --currency bitcoin \
  --ssh-password MySecurePass \
  --port 22:tcp \
  --port 8888:http

# 3. Revisa tus órdenes
clore orders

# 4. Conéctate por SSH al servidor
clore ssh 38

# 5. Cancela cuando termines
clore cancel 38

# 6. Revisa el saldo de la billetera
clore wallets
```

***

## Referencia de comandos CLI

| Comando                               | Descripción                                         |
| ------------------------------------- | --------------------------------------------------- |
| `clore search`                        | Buscar en el mercado de GPU                         |
| `clore deploy <server_id>`            | Crear una nueva orden                               |
| `clore orders`                        | Listar órdenes activas                              |
| `clore orders --completed`            | Listar todas las órdenes incluyendo las completadas |
| `clore ssh <order_id>`                | Conectarse por SSH a una orden activa               |
| `clore cancel <order_id>`             | Cancelar una orden                                  |
| `clore wallets`                       | Mostrar saldos de billeteras                        |
| `clore servers`                       | Listar tus servidores alojados                      |
| `clore server-config <name>`          | Mostrar configuración del servidor                  |
| `clore spot <server_id>`              | Ver el mercado spot para un servidor                |
| `clore spot-price <order_id> <price>` | Establecer precio spot para una orden               |
| `clore config set <key> <value>`      | Establecer valor de configuración                   |
| `clore config get <key>`              | Obtener valor de configuración                      |
| `clore config show`                   | Mostrar toda la configuración                       |

***

## Scripting con la CLI

### Desplegar y esperar por SSH

```bash
#!/bin/bash
# deploy-and-connect.sh — Desplegar un servidor y conectarse por SSH cuando esté listo

set -euo pipefail

SERVER_ID=${1:?Usage: $0 <server_id>}
IMAGE=${2:-cloreai/ubuntu22.04-cuda12}
PASSWORD="AutoDeploy$(date +%s)"

echo "🚀 Desplegando servidor $SERVER_ID..."
clore deploy "$SERVER_ID" \
  --image "$IMAGE" \
  --type on-demand \
  --currency bitcoin \
  --ssh-password "$PASSWORD" \
  --port 22:tcp

echo "⏳ Esperando a que la orden esté lista..."
sleep 15

echo "📦 Órdenes activas:"
clore orders

echo ""
echo "🔑 Contraseña SSH: $PASSWORD"
echo "💡 Conéctate con: clore ssh <order_id>"
```

### Encontrar la GPU más barata y desplegar

```bash
#!/bin/bash
# cheapest-gpu.sh — Encontrar y desplegar la GPU más barata que cumpla los criterios

GPU_MODEL=${1:-"RTX 4090"}
MAX_PRICE=${2:-5.0}

echo "🔍 Buscando la más barata $GPU_MODEL por debajo de \$$MAX_PRICE/h..."
clore search --gpu "$GPU_MODEL" --max-price "$MAX_PRICE" --sort price --limit 5

echo ""
read -p "Ingresa la ID del servidor para desplegar (o 'q' para salir): " SERVER_ID

if [ "$SERVER_ID" = "q" ]; then
    echo "Cancelado."
    exit 0
fi

read -sp "Contraseña SSH: " SSH_PASS
echo ""

clore deploy "$SERVER_ID" \
  --image cloreai/ubuntu22.04-cuda12 \
  --type on-demand \
  --currency bitcoin \
  --ssh-password "$SSH_PASS" \
  --port 22:tcp \
  --port 8888:http

echo "✅ ¡Desplegado! Revisa 'clore orders' para el estado."
```

### Cancelar todas las órdenes

```bash
#!/bin/bash
# cancel-all.sh — Cancelar todas las órdenes activas

echo "📦 Órdenes actuales:"
clore orders

echo ""
read -p "¿Cancelar TODAS las órdenes activas? (yes/no): " CONFIRM

if [ "$CONFIRM" = "yes" ]; then
    # Usa un one-liner de Python ya que la CLI cancela una a la vez
    python3 -c "
from clore_ai import CloreAI
client = CloreAI()
orders = client.my_orders()
for o in orders:
    client.cancel_order(o.id, issue='Batch cleanup')
    print(f'Cancelled order {o.id}')
print(f'Done. Cancelled {len(orders)} orders.')
"
else
    echo "Cancelado."
fi
```

***

## Integración CI/CD

### GitHub Actions: Desplegar GPU para entrenamiento

```yaml
# .github/workflows/train.yml
name: Entrenamiento con GPU

on:
  workflow_dispatch:
    inputs:
      gpu_model:
        description: 'Modelo de GPU'
        default: 'RTX 4090'
      max_price:
        description: 'Precio máximo USD/h'
        default: '2.0'

env:
  CLORE_API_KEY: ${{ secrets.CLORE_API_KEY }}

jobs:
  train:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install clore-ai
        run: pip install clore-ai

      - name: Find and deploy GPU
        run: |
          python3 << 'EOF'
          import time, os
          from clore_ai import CloreAI

          client = CloreAI()

          # Find cheapest matching GPU
          servers = client.marketplace(
              gpu="${{ github.event.inputs.gpu_model }}",
              max_price_usd=float("${{ github.event.inputs.max_price }}")
          )
          servers.sort(key=lambda s: s.price_usd or float("inf"))

          if not servers:
              print("No servers available!")
              exit(1)

          best = servers[0]
          print(f"Deploying on server {best.id}: {best.gpu_model} @ ${best.price_usd:.4f}/h")

          order = client.create_order(
              server_id=best.id,
              image="cloreai/ubuntu22.04-cuda12",
              type="on-demand",
              currency="bitcoin",
              ssh_password=os.environ.get("SSH_PASSWORD", "CITraining123"),
              ports={"22": "tcp"},
              command="bash /workspace/train.sh"
          )

          print(f"Order {order.id} created")

          # Wait for ready
          for _ in range(30):
              orders = client.my_orders()
              o = next((x for x in orders if x.id == order.id), None)
              if o and o.pub_cluster:
                  print(f"Ready: {o.pub_cluster}")
                  break
              time.sleep(10)

          # Save order ID for cleanup
          with open(os.environ["GITHUB_ENV"], "a") as f:
              f.write(f"ORDER_ID={order.id}\n")
          EOF

      - name: Wait for training to complete
        run: |
          echo "Entrenamiento en progreso..."
          # Agrega aquí tu lógica de monitoreo
          sleep 60

      - name: Cleanup GPU
        if: always()
        run: |
          python3 -c "
          from clore_ai import CloreAI
          import os
          client = CloreAI()
          order_id = int(os.environ.get('ORDER_ID', 0))
          if order_id:
              client.cancel_order(order_id, issue='CI job complete')
              print(f'Cancelled order {order_id}')
          "
```

### GitLab CI: Procesamiento por lotes

```yaml
# .gitlab-ci.yml
gpu-batch-job:
  stage: process
  image: python:3.11
  variables:
    CLORE_API_KEY: $CLORE_API_KEY
  before_script:
    - pip install clore-ai
  script:
    - |
      python3 << 'EOF'
      from clore_ai import CloreAI
      import time

      client = CloreAI()

      servers = client.marketplace(gpu="RTX 4090", max_price_usd=3.0)
      if not servers:
          print("No GPUs available")
          exit(1)

      servers.sort(key=lambda s: s.price_usd or float("inf"))
      order = client.create_order(
          server_id=servers[0].id,
          image="cloreai/ubuntu22.04-cuda12",
          type="spot",
          currency="bitcoin",
          spot_price=0.00005,
          ports={"22": "tcp"}
      )
      print(f"Deployed: order {order.id}")

      # ... realiza el trabajo ...

      client.cancel_order(order.id)
      print("Hecho y limpiado")
      EOF
  after_script:
    - |
      python3 -c "
      from clore_ai import CloreAI
      client = CloreAI()
      for o in client.my_orders():
          client.cancel_order(o.id, issue='CI cleanup')
      "
```

***

## Monitoreo

### Revisar órdenes periódicamente

```bash
#!/bin/bash
# monitor.sh — Revisar órdenes cada 60 segundos

while true; do
    echo "=== $(date) ==="
    clore orders
    clore wallets
    echo ""
    sleep 60
done
```

### Script de monitoreo en Python

```python
#!/usr/bin/env python3
"""monitor-orders.py — Monitorea órdenes activas y alerta sobre problemas."""

import time
from clore_ai import CloreAI

POLL_INTERVAL = 60  # segundos
LOW_BALANCE_THRESHOLD = 0.001  # BTC

def monitor():
    client = CloreAI()

    while True:
        try:
            # Revisar órdenes
            orders = client.my_orders()
            print(f"[{time.strftime('%H:%M:%S')}] Órdenes activas: {len(orders)}")
            for o in orders:
                print(f"  Orden {o.id}: tipo={o.type}, IP={o.pub_cluster or 'pendiente'}")

            # Revisar saldo
            wallets = client.wallets()
            for w in wallets:
                if w.name.lower() == "bitcoin" and w.balance < LOW_BALANCE_THRESHOLD:
                    print(f"  ⚠️  Saldo bajo de BTC: {w.balance:.8f}")

        except Exception as e:
            print(f"  ❌ Error: {e}")

        time.sleep(POLL_INTERVAL)

if __name__ == "__main__":
    monitor()
```

***

## Operaciones por lotes

### Desplegar en múltiples servidores

```bash
#!/bin/bash
# batch-deploy.sh — Desplegar en múltiples servidores

SERVER_IDS=(142 305 891 450)
IMAGE="cloreai/ubuntu22.04-cuda12"
PASSWORD="BatchRun$(date +%s)"

for SID in "${SERVER_IDS[@]}"; do
    echo "🚀 Desplegando en el servidor $SID..."
    clore deploy "$SID" \
      --image "$IMAGE" \
      --type on-demand \
      --currency bitcoin \
      --ssh-password "$PASSWORD" \
      --port 22:tcp \
      || echo "⚠️  Error al desplegar en $SID"
    sleep 6  # Respetar límites de tasa
done

echo ""
echo "📦 Todas las órdenes:"
clore orders
echo "🔑 Contraseña: $PASSWORD"
```

### Despliegue por lotes con Python (Async)

```python
#!/usr/bin/env python3
"""batch-deploy.py — Desplegar en múltiples servidores concurrentemente."""

import asyncio
from clore_ai import AsyncCloreAI
from clore_ai.exceptions import CloreAPIError

async def batch_deploy(server_ids, image="cloreai/ubuntu22.04-cuda12"):
    async with AsyncCloreAI() as client:
        tasks = [
            client.create_order(
                server_id=sid,
                image=image,
                type="on-demand",
                currency="bitcoin",
                ssh_password="BatchPass123",
                ports={"22": "tcp"}
            )
            for sid in server_ids
        ]

        results = await asyncio.gather(*tasks, return_exceptions=True)

        for sid, result in zip(server_ids, results):
            if isinstance(result, CloreAPIError):
                print(f"❌ Servidor {sid}: {result}")
            elif isinstance(result, Exception):
                print(f"❌ Servidor {sid}: {result}")
            else:
                print(f"✅ Servidor {sid}: Orden {result.id}")

if __name__ == "__main__":
    import sys
    server_ids = [int(x) for x in sys.argv[1:]]
    if not server_ids:
        print("Usage: python batch-deploy.py 142 305 891")
        exit(1)
    asyncio.run(batch_deploy(server_ids))
```

Uso:

```bash
python batch-deploy.py 142 305 891
```

### Escáner de mercado spot

```bash
#!/bin/bash
# spot-scanner.sh — Escanear precios spot para una lista de servidores

SERVERS=(6 12 42 100)

echo "📊 Escaneo de mercado spot — $(date)"
echo "---"

for SID in "${SERVERS[@]}"; do
    echo "Servidor $SID:"
    clore spot "$SID"
    echo ""
done
```

***

## Trabajos Cron

### Chequeo diario de precios de GPU

```bash
# Agrega al crontab: crontab -e
# Ejecutar todos los días a las 9 AM
0 9 * * * CLORE_API_KEY=your_key /usr/local/bin/clore search --gpu "RTX 4090" --sort price --limit 5 >> /var/log/clore-prices.log 2>&1
```

### Chequeo de saldo por hora

```bash
# Revisar saldo cada hora
0 * * * * CLORE_API_KEY=your_key /usr/local/bin/clore wallets >> /var/log/clore-balance.log 2>&1
```

***

## Consejos

1. **Siempre configura `CLORE_API_KEY`** como una variable de entorno en scripts y CI
2. **Añade `sleep 6`** entre comandos de despliegue en bucles bash para respetar los límites de tasa
3. **Usa `--type spot`** para trabajos por lotes/CI — más barato y aceptable que sea interrumpible
4. **Cancela órdenes en `after_script`** / `if: always()` para evitar facturación olvidada
5. **Almacena contraseñas SSH en secretos** (GitHub Secrets, Variables de GitLab CI, etc.)
6. **Usa `clore orders --completed`** para auditar el uso pasado

***

## Próximos pasos

* [Guía del SDK de Python](/guides/guides_v2-es/avanzado/python-sdk.md) — Referencia completa del SDK con patrones async
* [Procesamiento por lotes](/guides/guides_v2-es/avanzado/batch-processing.md) — Procesar grandes cargas de trabajo de IA
* [Integración de API](/guides/guides_v2-es/avanzado/api-integration.md) — Conectar servicios de IA a tus aplicaciones


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-es/avanzado/cli-automation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
