All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luis Chamberlain <mcgrof@kernel.org>
To: Chuck Lever <cel@kernel.org>, Daniel Gomez <da.gomez@kruces.com>,
	kdevops@lists.linux.dev
Cc: Luis Chamberlain <mcgrof@kernel.org>
Subject: [PATCH v2 09/10] scripts: add Lambda Labs testing and debugging utilities
Date: Wed, 27 Aug 2025 14:29:00 -0700	[thread overview]
Message-ID: <20250827212902.4021990-10-mcgrof@kernel.org> (raw)
In-Reply-To: <20250827212902.4021990-1-mcgrof@kernel.org>

Add utility scripts for testing, debugging, and managing Lambda Labs
cloud resources. These tools help developers validate configurations,
debug issues, and manage instances.

Testing utilities:
- Capacity checking before provisioning
- SSH connectivity testing
- API endpoint validation
- Credential verification

Management utilities:
- Instance listing and status checking
- Smart instance selection based on cost/availability
- Region inference for optimal placement
- Cloud provider comparison tool

Debugging utilities:
- API response exploration
- Debug script for troubleshooting API issues
- Instance update helper

Also documents the Lambda Labs implementation in PROMPTS.md for future
reference and improvement.

Generated-by: Claude AI
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
---
 PROMPTS.md                            |  56 ++++++++
 scripts/check_lambdalabs_capacity.py  | 172 ++++++++++++++++++++++
 scripts/cloud_list_all.sh             | 151 ++++++++++++++++++++
 scripts/debug_lambdalabs_api.sh       |  87 ++++++++++++
 scripts/explore_lambda_api.py         |  48 +++++++
 scripts/lambdalabs_infer_cheapest.py  | 107 ++++++++++++++
 scripts/lambdalabs_infer_region.py    |  36 +++++
 scripts/lambdalabs_list_instances.py  | 167 ++++++++++++++++++++++
 scripts/lambdalabs_smart_inference.py | 196 ++++++++++++++++++++++++++
 scripts/terraform_list_instances.sh   |  79 +++++++++++
 scripts/test_lambda_ssh.py            | 111 +++++++++++++++
 scripts/update_lambdalabs_instance.sh |  29 ++++
 12 files changed, 1239 insertions(+)
 create mode 100755 scripts/check_lambdalabs_capacity.py
 create mode 100755 scripts/cloud_list_all.sh
 create mode 100755 scripts/debug_lambdalabs_api.sh
 create mode 100644 scripts/explore_lambda_api.py
 create mode 100755 scripts/lambdalabs_infer_cheapest.py
 create mode 100755 scripts/lambdalabs_infer_region.py
 create mode 100755 scripts/lambdalabs_list_instances.py
 create mode 100755 scripts/lambdalabs_smart_inference.py
 create mode 100755 scripts/terraform_list_instances.sh
 create mode 100644 scripts/test_lambda_ssh.py
 create mode 100755 scripts/update_lambdalabs_instance.sh

diff --git a/PROMPTS.md b/PROMPTS.md
index 1b60cbe..c87a3b3 100644
--- a/PROMPTS.md
+++ b/PROMPTS.md
@@ -280,3 +280,59 @@ The implementation successfully added:
    to do is to use a separate fact if you want a true dynamic variable. This
    is why we switched to an active ref prefix for the baseline and dev group
    ref tags.
+
+## Cloud provider integrations
+
+### Adding Lambda Labs cloud provider support with dynamic Kconfig
+
+**Prompt:**
+The Lambda Labs company helps you use GPUs online, kind of like AWS, or OCI. Add
+support for the terraform support for Lambda Labs. The best provider docs are at
+https://registry.terraform.io/providers/elct9620/lambdalabs/latest/docs . Then
+To create the kconfig values you will implement support to use the lambda cloud
+API to let us query for what type of instances they have available and so forth.
+Therefore the Kconfig stuff for Lambda labs will all be dynamic. So we'll want
+to expand this as part of what make dynconfig does. However note that dynconfig
+does *all* dynamically generated kconfig. We want to add support for make
+cloud-config as a new target which is dynamic which is a subset of make
+dynconfig ;  OK! good luck
+
+**AI:** Claude Code (Opus 4.1)
+**Commit:** [To be determined]
+**Result:** Complete Lambda Labs integration with dynamic Kconfig generation.
+**Grading:** 75%
+
+**Notes:**
+
+The implementation successfully added:
+
+1. **Terraform Provider Integration**: Created complete Terraform configuration
+   for Lambda Labs including instance management, persistent storage, and SSH
+   configuration management following existing cloud provider patterns.
+
+2. **Dynamic Kconfig Generation**: Implemented Python script to query Lambda Labs
+   API for available instance types, regions, and OS images. Generated dynamic
+   Kconfig files with fallback defaults when API is unavailable.
+
+3. **Build System Integration**: Added `make cloud-config` as a new target for
+   cloud-specific dynamic configuration, properly integrated with `make dynconfig`.
+   Created modular Makefile structure for cloud provider dynamic configuration.
+
+4. **Kconfig Structure**: Properly integrated Lambda Labs into the provider
+   selection system with modular Kconfig files for location, compute, storage,
+   and identity management.
+
+Biggest issues:
+
+1. **SSH Management**: For this it failed to realize the provider
+   didn't suport asking for a custom username, so we had to find out the
+   hard way.
+
+2. **Environment variables**: For some reason it wanted to define the
+   credential API as an environment variable. This proved painful as some
+   environment variables do not carry over for some ansible tasks. The
+   best solution was to follow the strategy similar to what AWS supports
+   with ~/.lambdalabs/credentials. This a more secure alternative.
+
+Minor issues:
+- Some whitespace formatting was automatically fixed by the linter
diff --git a/scripts/check_lambdalabs_capacity.py b/scripts/check_lambdalabs_capacity.py
new file mode 100755
index 0000000..5b16156
--- /dev/null
+++ b/scripts/check_lambdalabs_capacity.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Check Lambda Labs capacity for a given instance type and region.
+Provides clear error messages when capacity is not available.
+"""
+
+import json
+import os
+import sys
+import urllib.request
+import urllib.error
+from typing import Dict, List, Optional
+
+# Import our credentials module
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+from lambdalabs_credentials import get_api_key as get_api_key_from_credentials
+
+LAMBDALABS_API_BASE = "https://cloud.lambdalabs.com/api/v1"
+
+
+def get_api_key() -> Optional[str]:
+    """Get Lambda Labs API key from credentials file or environment variable."""
+    return get_api_key_from_credentials()
+
+
+def check_capacity(instance_type: str, region: str) -> Dict:
+    """
+    Check if capacity is available for the given instance type and region.
+
+    Returns:
+        Dictionary with:
+        - available: bool - whether capacity is available
+        - message: str - human-readable message
+        - alternatives: list - alternative regions with capacity
+    """
+    api_key = get_api_key()
+    if not api_key:
+        return {
+            "available": False,
+            "message": "ERROR: Lambda Labs API key not configured.\n"
+            "Please configure your API key using:\n"
+            "  python3 scripts/lambdalabs_credentials.py set 'your-api-key'",
+            "alternatives": [],
+        }
+
+    headers = {"Authorization": f"Bearer {api_key}", "User-Agent": "kdevops/1.0"}
+    url = f"{LAMBDALABS_API_BASE}/instance-types"
+
+    try:
+        req = urllib.request.Request(url, headers=headers)
+        with urllib.request.urlopen(req) as response:
+            data = json.loads(response.read().decode())
+
+            if "data" not in data:
+                return {
+                    "available": False,
+                    "message": "ERROR: Invalid API response format",
+                    "alternatives": [],
+                }
+
+            # Check if instance type exists
+            if instance_type not in data["data"]:
+                available_types = list(data["data"].keys())[:10]
+                return {
+                    "available": False,
+                    "message": f"ERROR: Instance type '{instance_type}' does not exist.\n"
+                    f"Available instance types include: {', '.join(available_types)}",
+                    "alternatives": [],
+                }
+
+            gpu_info = data["data"][instance_type]
+
+            # Check if instance type is generally available
+            # Note: is_available can be None, True, or False
+            is_available = gpu_info.get("instance_type", {}).get("is_available")
+            if is_available is False:  # Only fail if explicitly False, not None
+                return {
+                    "available": False,
+                    "message": f"ERROR: Instance type '{instance_type}' is not currently available from Lambda Labs",
+                    "alternatives": [],
+                }
+
+            # Get regions with capacity
+            regions_with_capacity = gpu_info.get("regions_with_capacity_available", [])
+            region_names = [r["name"] for r in regions_with_capacity]
+
+            # Check if requested region has capacity
+            if region in region_names:
+                return {
+                    "available": True,
+                    "message": f"✓ Capacity is available for {instance_type} in {region}",
+                    "alternatives": region_names,
+                }
+            else:
+                # No capacity in requested region
+                if regions_with_capacity:
+                    alt_regions = [f"{r['name']}" for r in regions_with_capacity]
+                    return {
+                        "available": False,
+                        "message": f"ERROR: No capacity available for '{instance_type}' in region '{region}'.\n"
+                        f"\nRegions with available capacity:\n"
+                        + "\n".join([f"  • {r}" for r in alt_regions])
+                        + f"\n\nTo fix this issue, either:\n"
+                        f"1. Wait for capacity to become available in {region}\n"
+                        f"2. Change your region in menuconfig to one of the available regions\n"
+                        f"3. Choose a different instance type",
+                        "alternatives": region_names,
+                    }
+                else:
+                    return {
+                        "available": False,
+                        "message": f"ERROR: No capacity available for '{instance_type}' in ANY region.\n"
+                        f"This instance type is currently sold out across all Lambda Labs regions.\n"
+                        f"Please try:\n"
+                        f"  • A different instance type\n"
+                        f"  • Checking back later when capacity becomes available",
+                        "alternatives": [],
+                    }
+
+    except urllib.error.HTTPError as e:
+        if e.code == 403:
+            return {
+                "available": False,
+                "message": "ERROR: Lambda Labs API returned 403 Forbidden.\n"
+                "This usually means your API key is invalid, expired, or lacks permissions.\n"
+                "\n"
+                "To fix this:\n"
+                "1. Log into https://cloud.lambdalabs.com\n"
+                "2. Go to API Keys section\n"
+                "3. Create a new API key with full permissions\n"
+                "4. Update your credentials:\n"
+                '   python3 scripts/lambdalabs_credentials.py set "your-new-api-key"\n'
+                "\n"
+                "Current API key source: ~/.lambdalabs/credentials",
+                "alternatives": [],
+            }
+        else:
+            return {
+                "available": False,
+                "message": f"ERROR: API request failed with HTTP {e.code}: {e.reason}",
+                "alternatives": [],
+            }
+    except Exception as e:
+        return {
+            "available": False,
+            "message": f"ERROR: Failed to check capacity: {str(e)}",
+            "alternatives": [],
+        }
+
+
+def main():
+    """Main function for command-line usage."""
+    if len(sys.argv) != 3:
+        print("Usage: check_lambdalabs_capacity.py <instance_type> <region>")
+        print("Example: check_lambdalabs_capacity.py gpu_1x_a10 us-tx-1")
+        sys.exit(1)
+
+    instance_type = sys.argv[1]
+    region = sys.argv[2]
+
+    result = check_capacity(instance_type, region)
+
+    print(result["message"])
+
+    # Exit with appropriate code
+    sys.exit(0 if result["available"] else 1)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/cloud_list_all.sh b/scripts/cloud_list_all.sh
new file mode 100755
index 0000000..405c3d9
--- /dev/null
+++ b/scripts/cloud_list_all.sh
@@ -0,0 +1,151 @@
+#!/bin/bash
+# List all cloud instances across supported providers
+# Currently supports: Lambda Labs
+
+set -e
+
+PROVIDER=""
+
+# Detect which cloud provider is configured
+if [ -f .config ]; then
+    if grep -q "CONFIG_TERRAFORM_LAMBDALABS=y" .config 2>/dev/null; then
+        PROVIDER="lambdalabs"
+    elif grep -q "CONFIG_TERRAFORM_AWS=y" .config 2>/dev/null; then
+        PROVIDER="aws"
+    elif grep -q "CONFIG_TERRAFORM_GCE=y" .config 2>/dev/null; then
+        PROVIDER="gce"
+    elif grep -q "CONFIG_TERRAFORM_AZURE=y" .config 2>/dev/null; then
+        PROVIDER="azure"
+    elif grep -q "CONFIG_TERRAFORM_OCI=y" .config 2>/dev/null; then
+        PROVIDER="oci"
+    fi
+fi
+
+if [ -z "$PROVIDER" ]; then
+    echo "No cloud provider configured or .config file not found"
+    exit 1
+fi
+
+echo "Cloud Provider: $PROVIDER"
+echo
+
+case "$PROVIDER" in
+    lambdalabs)
+        # Get API key from credentials file
+        API_KEY=$(python3 $(dirname "$0")/lambdalabs_credentials.py get 2>/dev/null)
+        if [ -z "$API_KEY" ]; then
+            echo "Error: Lambda Labs API key not found"
+            echo "Please configure it with: python3 scripts/lambdalabs_credentials.py set 'your-api-key'"
+            exit 1
+        fi
+
+        # Try to list instances using curl
+        echo "Fetching Lambda Labs instances..."
+        response=$(curl -s -H "Authorization: Bearer $API_KEY" \
+            https://cloud.lambdalabs.com/api/v1/instances 2>&1)
+
+        # Check if we got an error
+        if echo "$response" | grep -q '"error"'; then
+            echo "Error accessing Lambda Labs API:"
+            echo "$response" | python3 -c "
+import sys, json
+try:
+    data = json.load(sys.stdin)
+    if 'error' in data:
+        err = data['error']
+        print(f\"  {err.get('message', 'Unknown error')}\")
+        if 'suggestion' in err:
+            print(f\"  Suggestion: {err['suggestion']}\")
+except:
+    print('  Unable to parse error response')
+"
+            exit 1
+        fi
+
+        # Parse and display instances
+        echo "$response" | python3 -c '
+import sys, json
+from datetime import datetime
+
+def format_uptime(created_at):
+    try:
+        created = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
+        now = datetime.now(created.tzinfo)
+        delta = now - created
+
+        days = delta.days
+        hours, remainder = divmod(delta.seconds, 3600)
+        minutes, _ = divmod(remainder, 60)
+
+        if days > 0:
+            return f"{days}d {hours}h {minutes}m"
+        elif hours > 0:
+            return f"{hours}h {minutes}m"
+        else:
+            return f"{minutes}m"
+    except:
+        return "unknown"
+
+data = json.load(sys.stdin)
+instances = data.get("data", [])
+
+if not instances:
+    print("No Lambda Labs instances currently running")
+else:
+    print("Lambda Labs Instances:")
+    print("=" * 80)
+    headers = f"{'Name':<20} {'Type':<20} {'IP':<15} {'Region':<15} {'Status':<10}"
+    print(headers)
+    print("-" * 80)
+
+    total_cost = 0
+    for inst in instances:
+        name = inst.get("name", "unnamed")
+        inst_type = inst.get("instance_type", {}).get("name", "unknown")
+        ip = inst.get("ip", "pending")
+        region = inst.get("region", {}).get("name", "unknown")
+        status = inst.get("status", "unknown")
+
+        # Highlight kdevops instances
+        if "cgpu" in name or "kdevops" in name.lower():
+            name = f"→ {name}"
+
+        row = f"{name:<20} {inst_type:<20} {ip:<15} {region:<15} {status:<10}"
+        print(row)
+
+        price_cents = inst.get("instance_type", {}).get("price_cents_per_hour", 0)
+        total_cost += price_cents / 100
+
+    print("-" * 80)
+    print(f"Total instances: {len(instances)}")
+    if total_cost > 0:
+        print(f"Total hourly cost: ${total_cost:.2f}/hr")
+        print(f"Daily cost estimate: ${total_cost * 24:.2f}/day")
+'
+        ;;
+
+    aws)
+        echo "AWS cloud listing not yet implemented"
+        echo "You can use: aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,InstanceType,PublicIpAddress,State.Name,Tags[?Key==\`Name\`]|[0].Value]' --output table"
+        ;;
+
+    gce)
+        echo "Google Cloud listing not yet implemented"
+        echo "You can use: gcloud compute instances list"
+        ;;
+
+    azure)
+        echo "Azure cloud listing not yet implemented"
+        echo "You can use: az vm list --output table"
+        ;;
+
+    oci)
+        echo "Oracle Cloud listing not yet implemented"
+        echo "You can use: oci compute instance list --compartment-id <compartment-ocid>"
+        ;;
+
+    *)
+        echo "Cloud provider '$PROVIDER' not supported for listing"
+        exit 1
+        ;;
+esac
diff --git a/scripts/debug_lambdalabs_api.sh b/scripts/debug_lambdalabs_api.sh
new file mode 100755
index 0000000..d9b5b15
--- /dev/null
+++ b/scripts/debug_lambdalabs_api.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+echo "Lambda Labs API Diagnostic Script"
+echo "================================="
+echo
+
+# Get API key from credentials file
+API_KEY=$(python3 $(dirname "$0")/lambdalabs_credentials.py get 2>/dev/null)
+if [ -z "$API_KEY" ]; then
+    echo "❌ Lambda Labs API key not found"
+    echo "   Please configure it with: python3 scripts/lambdalabs_credentials.py set 'your-api-key'"
+    exit 1
+else
+    echo "✓ Lambda Labs API key loaded from credentials"
+    echo "  Key starts with: ${API_KEY:0:10}..."
+    echo "  Key length: ${#API_KEY} characters"
+fi
+
+echo
+echo "Testing API Access:"
+echo "-------------------"
+
+# Test with curl to get more detailed error information
+echo "1. Testing instance types endpoint..."
+response=$(curl -s -w "\n%{http_code}" -H "Authorization: Bearer $API_KEY" \
+    https://cloud.lambdalabs.com/api/v1/instance-types 2>&1)
+http_code=$(echo "$response" | tail -n 1)
+body=$(echo "$response" | head -n -1)
+
+if [ "$http_code" = "200" ]; then
+    echo "   ✓ API access successful"
+    echo "   Instance types available: $(echo "$body" | grep -o '"name"' | wc -l)"
+elif [ "$http_code" = "403" ]; then
+    echo "   ❌ Access forbidden (HTTP 403)"
+    echo "   Error: $body"
+    echo
+    echo "   Possible causes:"
+    echo "   - Invalid or expired API key"
+    echo "   - API key doesn't have necessary permissions"
+    echo "   - IP address or region restrictions"
+    echo "   - Rate limiting"
+    echo
+    echo "   Please verify:"
+    echo "   1. Your API key is correct and active"
+    echo "   2. You're not behind a VPN that might be blocked"
+    echo "   3. Your Lambda Labs account is in good standing"
+elif [ "$http_code" = "401" ]; then
+    echo "   ❌ Unauthorized (HTTP 401)"
+    echo "   Your API key appears to be invalid or malformed"
+else
+    echo "   ❌ Unexpected response (HTTP $http_code)"
+    echo "   Response: $body"
+fi
+
+echo
+echo "2. Testing SSH keys endpoint..."
+response=$(curl -s -w "\n%{http_code}" -H "Authorization: Bearer $API_KEY" \
+    https://cloud.lambdalabs.com/api/v1/ssh-keys 2>&1)
+http_code=$(echo "$response" | tail -n 1)
+body=$(echo "$response" | head -n -1)
+
+if [ "$http_code" = "200" ]; then
+    echo "   ✓ Can access SSH keys"
+    # Try to find the kdevops key
+    if echo "$body" | grep -q "kdevops-lambdalabs"; then
+        echo "   ✓ Found 'kdevops-lambdalabs' SSH key"
+    else
+        echo "   ⚠ 'kdevops-lambdalabs' SSH key not found"
+        echo "   Available keys:"
+        echo "$body" | grep -o '"name":"[^"]*"' | sed 's/"name":"/ - /g' | sed 's/"//g'
+    fi
+else
+    echo "   ❌ Cannot access SSH keys (HTTP $http_code)"
+fi
+
+echo
+echo "Troubleshooting Steps:"
+echo "----------------------"
+echo "1. Verify your API key at: https://cloud.lambdalabs.com/api-keys"
+echo "2. Create a new API key if needed"
+echo "3. Ensure you're not using a VPN that might be blocked"
+echo "4. Try accessing the API from a different network/location"
+echo "5. Contact Lambda Labs support if the issue persists"
+echo
+echo "For manual testing, try:"
+echo "API_KEY=\$(python3 scripts/lambdalabs_credentials.py get)"
+echo "curl -H \"Authorization: Bearer \$API_KEY\" https://cloud.lambdalabs.com/api/v1/instance-types"
diff --git a/scripts/explore_lambda_api.py b/scripts/explore_lambda_api.py
new file mode 100644
index 0000000..8c07547
--- /dev/null
+++ b/scripts/explore_lambda_api.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+"""Explore Lambda Labs API to understand SSH key management."""
+
+import json
+import sys
+import os
+
+# Add scripts directory to path
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+from lambdalabs_credentials import get_api_key
+
+# Try to get docs
+print("Lambda Labs API SSH Key Management")
+print("=" * 50)
+print()
+print("Based on API exploration, here's what we know:")
+print()
+print("1. SSH Keys Endpoint: /ssh-keys")
+print("   - GET /ssh-keys returns a list of key NAMES only")
+print("   - The API returns: {'data': ['key-name-1', 'key-name-2', ...]}")
+print()
+print("2. Deleting Keys:")
+print("   - DELETE /ssh-keys/{key_id} expects a key ID, not a name")
+print("   - The error 'Invalid SSH key ID' suggests IDs are different from names")
+print("   - The IDs might be UUIDs or other internal identifiers")
+print()
+print("3. Adding Keys:")
+print(
+    "   - POST /ssh-keys likely works with {name: 'key-name', public_key: 'ssh-rsa ...'}"
+)
+print()
+print("4. The problem:")
+print("   - GET /ssh-keys only returns names")
+print("   - DELETE /ssh-keys/{id} requires IDs")
+print("   - There's no apparent way to get the ID from the name")
+print()
+print("Possible solutions:")
+print("1. There might be a GET /ssh-keys?detailed=true or similar")
+print("2. The key names might BE the IDs (but delete fails)")
+print("3. There might be a separate endpoint to get key details")
+print("4. The API might be incomplete/broken for key deletion")
+print()
+print("To properly use kdevops with Lambda Labs, we should use")
+print("the key name 'kdevops-lambdalabs' as configured in Kconfig.")
+print()
+print("Since we can list keys but not delete them via API,")
+print("users must manage keys through the web console:")
+print("https://cloud.lambdalabs.com/ssh-keys")
diff --git a/scripts/lambdalabs_infer_cheapest.py b/scripts/lambdalabs_infer_cheapest.py
new file mode 100755
index 0000000..52c62c3
--- /dev/null
+++ b/scripts/lambdalabs_infer_cheapest.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Find the cheapest available Lambda Labs instance type.
+"""
+
+import json
+import sys
+import urllib.request
+import urllib.error
+from typing import Optional, List, Dict, Tuple
+
+# Import our credentials module
+sys.path.insert(0, sys.path[0])
+from lambdalabs_credentials import get_api_key
+
+LAMBDALABS_API_BASE = "https://cloud.lambdalabs.com/api/v1"
+
+# Known pricing for Lambda Labs instances (per hour)
+INSTANCE_PRICING = {
+    "gpu_1x_rtx6000": 0.50,
+    "gpu_1x_a10": 0.75,
+    "gpu_1x_a6000": 0.80,
+    "gpu_1x_a100": 1.29,
+    "gpu_1x_a100_sxm4": 1.29,
+    "gpu_1x_a100_pcie": 1.29,
+    "gpu_1x_gh200": 1.49,
+    "gpu_1x_h100_pcie": 2.49,
+    "gpu_1x_h100_sxm5": 3.29,
+    "gpu_2x_a100": 2.58,
+    "gpu_2x_a100_pcie": 2.58,
+    "gpu_2x_a6000": 1.60,
+    "gpu_2x_h100_sxm5": 6.38,
+    "gpu_4x_a100": 5.16,
+    "gpu_4x_a100_pcie": 5.16,
+    "gpu_4x_a6000": 3.20,
+    "gpu_4x_h100_sxm5": 12.36,
+    "gpu_8x_v100": 4.40,
+    "gpu_8x_a100": 10.32,
+    "gpu_8x_a100_40gb": 10.32,
+    "gpu_8x_a100_80gb": 14.32,
+    "gpu_8x_a100_80gb_sxm4": 14.32,
+    "gpu_8x_h100_sxm5": 23.92,
+    "gpu_8x_b200_sxm6": 39.92,
+}
+
+
+def get_cheapest_available_instance() -> Optional[str]:
+    """
+    Find the cheapest instance type with available capacity.
+
+    Returns:
+        Instance type name of cheapest available option
+    """
+    api_key = get_api_key()
+    if not api_key:
+        # Return a reasonable default if no API key
+        return "gpu_1x_a10"
+
+    headers = {"Authorization": f"Bearer {api_key}", "User-Agent": "kdevops/1.0"}
+    url = f"{LAMBDALABS_API_BASE}/instance-types"
+
+    try:
+        req = urllib.request.Request(url, headers=headers)
+        with urllib.request.urlopen(req) as response:
+            data = json.loads(response.read().decode())
+
+            if "data" not in data:
+                return "gpu_1x_a10"
+
+            # Find all instance types with available capacity
+            available_instances = []
+
+            for instance_type, info in data["data"].items():
+                regions_with_capacity = info.get("regions_with_capacity_available", [])
+                if regions_with_capacity:
+                    # This instance has capacity somewhere
+                    price = INSTANCE_PRICING.get(instance_type, 999.99)
+                    available_instances.append((instance_type, price))
+
+            if not available_instances:
+                # No capacity anywhere, return cheapest known instance
+                return "gpu_1x_a10"
+
+            # Sort by price (lowest first)
+            available_instances.sort(key=lambda x: x[1])
+
+            # Return the cheapest available instance type
+            return available_instances[0][0]
+
+    except Exception as e:
+        # On any error, return default
+        return "gpu_1x_a10"
+
+
+def main():
+    """Main function for command-line usage."""
+    instance = get_cheapest_available_instance()
+    if instance:
+        print(instance)
+    else:
+        print("gpu_1x_a10")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/lambdalabs_infer_region.py b/scripts/lambdalabs_infer_region.py
new file mode 100755
index 0000000..d8fea17
--- /dev/null
+++ b/scripts/lambdalabs_infer_region.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Smart region inference for Lambda Labs.
+Uses the smart inference algorithm to find the best region for a given instance type.
+"""
+
+import sys
+import os
+
+# Import the smart inference module
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+from lambdalabs_smart_inference import get_best_instance_and_region
+
+
+def main():
+    """Main function for command-line usage."""
+    if len(sys.argv) != 2:
+        print("us-east-1")  # Default
+        sys.exit(0)
+
+    # The instance type is passed but we'll get the best region from smart inference
+    # This maintains backward compatibility while using the smart algorithm
+    instance_type_requested = sys.argv[1]
+
+    # Get the best instance and region combo
+    best_instance, best_region = get_best_instance_and_region()
+
+    # For now, just return the best region
+    # In the future, we could check if the requested instance is available in the best region
+    print(best_region)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/lambdalabs_list_instances.py b/scripts/lambdalabs_list_instances.py
new file mode 100755
index 0000000..c61b701
--- /dev/null
+++ b/scripts/lambdalabs_list_instances.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python3
+"""
+List all Lambda Labs instances for the current account.
+Part of kdevops cloud management utilities.
+"""
+
+import os
+import sys
+import json
+import urllib.request
+import urllib.error
+from datetime import datetime
+import lambdalabs_credentials
+
+
+def format_uptime(created_at):
+    """Convert timestamp to human-readable uptime."""
+    try:
+        created = datetime.fromisoformat(created_at.replace("Z", "+00:00"))
+        now = datetime.now(created.tzinfo)
+        delta = now - created
+
+        days = delta.days
+        hours, remainder = divmod(delta.seconds, 3600)
+        minutes, _ = divmod(remainder, 60)
+
+        if days > 0:
+            return f"{days}d {hours}h {minutes}m"
+        elif hours > 0:
+            return f"{hours}h {minutes}m"
+        else:
+            return f"{minutes}m"
+    except:
+        return "unknown"
+
+
+def list_instances():
+    """List all Lambda Labs instances."""
+    # Get API key from credentials
+    api_key = lambdalabs_credentials.get_api_key()
+    if not api_key:
+        print(
+            "Error: Lambda Labs API key not found in credentials file", file=sys.stderr
+        )
+        print(
+            "Please configure it with: python3 scripts/lambdalabs_credentials.py set 'your-api-key'",
+            file=sys.stderr,
+        )
+        return 1
+
+    url = "https://cloud.lambdalabs.com/api/v1/instances"
+    headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
+
+    try:
+        req = urllib.request.Request(url, headers=headers)
+        with urllib.request.urlopen(req) as response:
+            data = json.loads(response.read().decode())
+
+            if "data" not in data:
+                print("No instances found or unexpected API response")
+                return 0
+
+            instances = data["data"]
+
+            if not instances:
+                print("No Lambda Labs instances currently running")
+                return 0
+
+            # Print header
+            print("\nLambda Labs Instances:")
+            print("=" * 80)
+            print(
+                f"{'Name':<20} {'Type':<20} {'IP':<15} {'Region':<15} {'Uptime':<10} {'Status'}"
+            )
+            print("-" * 80)
+
+            # Print each instance
+            for instance in instances:
+                name = instance.get("name", "unnamed")
+                instance_type = instance.get("instance_type", {}).get("name", "unknown")
+                ip = instance.get("ip", "pending")
+                region = instance.get("region", {}).get("name", "unknown")
+                status = instance.get("status", "unknown")
+                created_at = instance.get("created", "")
+                uptime = format_uptime(created_at)
+
+                # Highlight kdevops instances
+                if "cgpu" in name or "kdevops" in name.lower():
+                    name = f"→ {name}"
+
+                print(
+                    f"{name:<20} {instance_type:<20} {ip:<15} {region:<15} {uptime:<10} {status}"
+                )
+
+            print("-" * 80)
+            print(f"Total instances: {len(instances)}")
+
+            # Calculate total cost
+            total_cost = 0
+            for instance in instances:
+                price_cents = instance.get("instance_type", {}).get(
+                    "price_cents_per_hour", 0
+                )
+                total_cost += price_cents / 100
+
+            if total_cost > 0:
+                print(f"Total hourly cost: ${total_cost:.2f}/hr")
+                print(f"Daily cost estimate: ${total_cost * 24:.2f}/day")
+
+            print()
+
+            return 0
+
+    except urllib.error.HTTPError as e:
+        error_body = e.read().decode()
+        print(f"Error: HTTP {e.code} - {e.reason}", file=sys.stderr)
+        if error_body:
+            try:
+                error_data = json.loads(error_body)
+                if "error" in error_data:
+                    err = error_data["error"]
+                    print(f"  {err.get('message', 'Unknown error')}", file=sys.stderr)
+                    if "suggestion" in err:
+                        print(f"  Suggestion: {err['suggestion']}", file=sys.stderr)
+            except:
+                print(f"  Response: {error_body}", file=sys.stderr)
+        return 1
+    except Exception as e:
+        print(f"Error: {e}", file=sys.stderr)
+        return 1
+
+
+def main():
+    """Main entry point."""
+    # Support JSON output flag
+    if len(sys.argv) > 1 and sys.argv[1] == "--json":
+        # For future: output raw JSON
+        # Get API key from credentials
+        api_key = lambdalabs_credentials.get_api_key()
+        if not api_key:
+            print(
+                json.dumps(
+                    {"error": "Lambda Labs API key not found in credentials file"}
+                )
+            )
+            return 1
+
+        url = "https://cloud.lambdalabs.com/api/v1/instances"
+        headers = {
+            "Authorization": f"Bearer {api_key}",
+            "Content-Type": "application/json",
+        }
+
+        try:
+            req = urllib.request.Request(url, headers=headers)
+            with urllib.request.urlopen(req) as response:
+                print(response.read().decode())
+                return 0
+        except Exception as e:
+            print(json.dumps({"error": str(e)}))
+            return 1
+    else:
+        return list_instances()
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/scripts/lambdalabs_smart_inference.py b/scripts/lambdalabs_smart_inference.py
new file mode 100755
index 0000000..fa59d76
--- /dev/null
+++ b/scripts/lambdalabs_smart_inference.py
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Smart inference for Lambda Labs - finds cheapest instance preferring closer regions.
+Algorithm:
+1. Determine user's location from public IP
+2. Find all available instance/region combinations
+3. Group by price tier (instances with same price)
+4. For each price tier, select the closest region
+5. Return the cheapest tier's best region/instance combo
+"""
+
+import json
+import sys
+import urllib.request
+import urllib.error
+from typing import Optional, List, Dict, Tuple
+import math
+
+# Import our credentials module
+sys.path.insert(0, sys.path[0])
+from lambdalabs_credentials import get_api_key
+
+LAMBDALABS_API_BASE = "https://cloud.lambdalabs.com/api/v1"
+
+# Known pricing for Lambda Labs instances (per hour)
+INSTANCE_PRICING = {
+    "gpu_1x_rtx6000": 0.50,
+    "gpu_1x_a10": 0.75,
+    "gpu_1x_a6000": 0.80,
+    "gpu_1x_a100": 1.29,
+    "gpu_1x_a100_sxm4": 1.29,
+    "gpu_1x_a100_pcie": 1.29,
+    "gpu_1x_gh200": 1.49,
+    "gpu_1x_h100_pcie": 2.49,
+    "gpu_1x_h100_sxm5": 3.29,
+    "gpu_2x_a100": 2.58,
+    "gpu_2x_a100_pcie": 2.58,
+    "gpu_2x_a6000": 1.60,
+    "gpu_2x_h100_sxm5": 6.38,
+    "gpu_4x_a100": 5.16,
+    "gpu_4x_a100_pcie": 5.16,
+    "gpu_4x_a6000": 3.20,
+    "gpu_4x_h100_sxm5": 12.36,
+    "gpu_8x_v100": 4.40,
+    "gpu_8x_a100": 10.32,
+    "gpu_8x_a100_40gb": 10.32,
+    "gpu_8x_a100_80gb": 14.32,
+    "gpu_8x_a100_80gb_sxm4": 14.32,
+    "gpu_8x_h100_sxm5": 23.92,
+    "gpu_8x_b200_sxm6": 39.92,
+}
+
+# Approximate region locations (latitude, longitude)
+REGION_LOCATIONS = {
+    "us-east-1": (39.0458, -77.6413),  # Virginia
+    "us-west-1": (37.3541, -121.9552),  # California (San Jose)
+    "us-west-2": (45.5152, -122.6784),  # Oregon
+    "us-west-3": (33.4484, -112.0740),  # Arizona
+    "us-tx-1": (30.2672, -97.7431),  # Texas (Austin)
+    "us-midwest-1": (41.8781, -87.6298),  # Illinois (Chicago)
+    "us-south-1": (33.7490, -84.3880),  # Georgia (Atlanta)
+    "us-south-2": (29.7604, -95.3698),  # Texas (Houston)
+    "us-south-3": (25.7617, -80.1918),  # Florida (Miami)
+    "europe-central-1": (50.1109, 8.6821),  # Frankfurt
+    "asia-northeast-1": (35.6762, 139.6503),  # Tokyo
+    "asia-south-1": (19.0760, 72.8777),  # Mumbai
+    "me-west-1": (25.2048, 55.2708),  # Dubai
+    "australia-east-1": (-33.8688, 151.2093),  # Sydney
+}
+
+
+def get_user_location() -> Tuple[float, float]:
+    """
+    Get user's approximate location from public IP.
+    Returns (latitude, longitude) tuple.
+    """
+    try:
+        # Try to get location from IP
+        with urllib.request.urlopen("http://ip-api.com/json/", timeout=2) as response:
+            data = json.loads(response.read().decode())
+            if data.get("status") == "success":
+                return (data.get("lat", 39.0458), data.get("lon", -77.6413))
+    except:
+        pass
+
+    # Default to US East Coast if can't determine
+    return (39.0458, -77.6413)
+
+
+def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
+    """
+    Calculate approximate distance between two points using Haversine formula.
+    Returns distance in kilometers.
+    """
+    R = 6371  # Earth's radius in kilometers
+
+    lat1_rad = math.radians(lat1)
+    lat2_rad = math.radians(lat2)
+    delta_lat = math.radians(lat2 - lat1)
+    delta_lon = math.radians(lon2 - lon1)
+
+    a = (
+        math.sin(delta_lat / 2) ** 2
+        + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon / 2) ** 2
+    )
+    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
+
+    return R * c
+
+
+def get_best_instance_and_region() -> Tuple[str, str]:
+    """
+    Find the cheapest available instance, preferring closer regions when same price.
+
+    Returns:
+        (instance_type, region) tuple
+    """
+    api_key = get_api_key()
+    if not api_key:
+        # Return defaults if no API key
+        return ("gpu_1x_a10", "us-west-1")
+
+    # Get user's location
+    user_lat, user_lon = get_user_location()
+
+    headers = {"Authorization": f"Bearer {api_key}", "User-Agent": "kdevops/1.0"}
+    url = f"{LAMBDALABS_API_BASE}/instance-types"
+
+    try:
+        req = urllib.request.Request(url, headers=headers)
+        with urllib.request.urlopen(req) as response:
+            data = json.loads(response.read().decode())
+
+            if "data" not in data:
+                return ("gpu_1x_a10", "us-west-1")
+
+            # Build a map of price -> list of (instance, region, distance) tuples
+            price_tiers = {}
+
+            for instance_type, info in data["data"].items():
+                regions_with_capacity = info.get("regions_with_capacity_available", [])
+                if regions_with_capacity:
+                    price = INSTANCE_PRICING.get(instance_type, 999.99)
+
+                    for region_info in regions_with_capacity:
+                        region = region_info.get("name")
+                        if region and region in REGION_LOCATIONS:
+                            region_lat, region_lon = REGION_LOCATIONS[region]
+                            distance = calculate_distance(
+                                user_lat, user_lon, region_lat, region_lon
+                            )
+
+                            if price not in price_tiers:
+                                price_tiers[price] = []
+                            price_tiers[price].append((instance_type, region, distance))
+
+            if not price_tiers:
+                # No capacity anywhere
+                return ("gpu_1x_a10", "us-west-1")
+
+            # Sort price tiers by price
+            sorted_prices = sorted(price_tiers.keys())
+
+            # For the cheapest price tier, find the closest region
+            cheapest_price = sorted_prices[0]
+            options = price_tiers[cheapest_price]
+
+            # Sort by distance to find closest
+            options.sort(key=lambda x: x[2])
+            best_instance, best_region, best_distance = options[0]
+
+            return (best_instance, best_region)
+
+    except Exception as e:
+        # On any error, return defaults (west for SF user)
+        return ("gpu_1x_a10", "us-west-1")
+
+
+def main():
+    """Main function for command-line usage."""
+    mode = sys.argv[1] if len(sys.argv) > 1 else "both"
+
+    instance, region = get_best_instance_and_region()
+
+    if mode == "instance":
+        print(instance)
+    elif mode == "region":
+        print(region)
+    else:  # both
+        print(f"{instance},{region}")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/terraform_list_instances.sh b/scripts/terraform_list_instances.sh
new file mode 100755
index 0000000..0a98363
--- /dev/null
+++ b/scripts/terraform_list_instances.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+# List instances from terraform state
+# This works even when API access is limited
+
+set -e
+
+# Function to detect terraform directory based on cloud provider
+get_terraform_dir() {
+    if [ -f .config ]; then
+        if grep -q "CONFIG_TERRAFORM_LAMBDALABS=y" .config 2>/dev/null; then
+            echo "terraform/lambdalabs"
+        elif grep -q "CONFIG_TERRAFORM_AWS=y" .config 2>/dev/null; then
+            echo "terraform/aws"
+        elif grep -q "CONFIG_TERRAFORM_GCE=y" .config 2>/dev/null; then
+            echo "terraform/gce"
+        elif grep -q "CONFIG_TERRAFORM_AZURE=y" .config 2>/dev/null; then
+            echo "terraform/azure"
+        elif grep -q "CONFIG_TERRAFORM_OCI=y" .config 2>/dev/null; then
+            echo "terraform/oci"
+        elif grep -q "CONFIG_TERRAFORM_OPENSTACK=y" .config 2>/dev/null; then
+            echo "terraform/openstack"
+        else
+            echo ""
+        fi
+    else
+        echo ""
+    fi
+}
+
+# Get terraform directory
+TERRAFORM_DIR=$(get_terraform_dir)
+
+if [ -z "$TERRAFORM_DIR" ]; then
+    echo "No terraform provider configured"
+    exit 1
+fi
+
+if [ ! -d "$TERRAFORM_DIR" ]; then
+    echo "Terraform directory $TERRAFORM_DIR does not exist"
+    exit 1
+fi
+
+cd "$TERRAFORM_DIR"
+
+# Check if terraform is initialized
+if [ ! -d ".terraform" ]; then
+    echo "Terraform not initialized. Run 'make' first."
+    exit 1
+fi
+
+# Check if we have state
+if [ ! -f "terraform.tfstate" ]; then
+    echo "No terraform state file found. No instances deployed."
+    exit 0
+fi
+
+echo "Terraform Managed Instances:"
+echo "============================"
+echo
+
+# Try to get instances from state
+terraform state list 2>/dev/null | grep -E "instance|vm" | while read resource; do
+    echo "Resource: $resource"
+    terraform state show "$resource" 2>/dev/null | grep -E "^\s*(name|ip|ip_address|public_ip|instance_type|region|status|hostname)" | sed 's/^/  /'
+    echo
+done
+
+# If no instances found
+if ! terraform state list 2>/dev/null | grep -qE "instance|vm"; then
+    echo "No instances found in terraform state"
+    echo
+    echo "To deploy instances, run: make bringup"
+fi
+
+# Show outputs if available
+echo
+echo "Terraform Outputs:"
+echo "-----------------"
+terraform output 2>/dev/null || echo "No outputs defined"
diff --git a/scripts/test_lambda_ssh.py b/scripts/test_lambda_ssh.py
new file mode 100644
index 0000000..5034697
--- /dev/null
+++ b/scripts/test_lambda_ssh.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+
+import os
+import json
+import urllib.request
+import urllib.error
+import lambdalabs_credentials
+
+# Get API key from credentials file
+# Get API key from credentials
+api_key = lambdalabs_credentials.get_api_key()
+if not api_key:
+    print("No Lambda Labs API key found in credentials file")
+    print(
+        "Please configure it with: python3 scripts/lambdalabs_credentials.py set 'your-api-key'"
+    )
+    exit(1)
+
+print(f"API Key length: {len(api_key)}")
+print(f"API Key prefix: {api_key[:30]}...")
+
+
+def make_request(endpoint, method="GET", data=None):
+    """Make API request to Lambda Labs"""
+    url = f"https://cloud.lambdalabs.com/api/v1{endpoint}"
+
+    headers = {
+        "Authorization": f"Bearer {api_key}",
+        "User-Agent": "kdevops/1.0",
+        "Accept": "application/json",
+        "Content-Type": "application/json",
+    }
+
+    req_data = None
+    if data and method in ["POST", "PUT", "PATCH", "DELETE"]:
+        req_data = json.dumps(data).encode("utf-8")
+
+    try:
+        req = urllib.request.Request(url, headers=headers, data=req_data, method=method)
+        with urllib.request.urlopen(req) as response:
+            content = response.read().decode()
+            if content:
+                return json.loads(content)
+            return {"status": "success"}
+    except urllib.error.HTTPError as e:
+        print(f"\nHTTP Error {e.code} for {method} {endpoint}")
+        try:
+            error_content = e.read().decode()
+            error_data = json.loads(error_content)
+            print(f"Error: {json.dumps(error_data, indent=2)}")
+        except:
+            print(f"Error response: {error_content[:500]}")
+        return None
+    except Exception as e:
+        print(f"\nException for {method} {endpoint}: {e}")
+        return None
+
+
+# Test different endpoints
+print("\n1. Testing /instances endpoint...")
+result = make_request("/instances")
+if result and "data" in result:
+    print(f"   ✓ Instances: Found {len(result['data'])} instances")
+else:
+    print("   ✗ Instances endpoint failed")
+
+print("\n2. Testing /instance-types endpoint...")
+result = make_request("/instance-types")
+if result and "data" in result:
+    print(f"   ✓ Instance types: Found {len(result['data'])} types")
+else:
+    print("   ✗ Instance types endpoint failed")
+
+print("\n3. Testing /ssh-keys endpoint...")
+result = make_request("/ssh-keys")
+if result:
+    print(f"   ✓ SSH Keys endpoint works!")
+    if "data" in result:
+        keys = result["data"]
+        print(f"   Found {len(keys)} SSH keys:")
+        for key in keys:
+            if isinstance(key, dict):
+                name = key.get("name", key.get("id", "unknown"))
+                print(f"     - {name}")
+            else:
+                print(f"     - {key}")
+
+        # Try to delete keys
+        print("\n4. Attempting to delete SSH keys...")
+        for key in keys:
+            if isinstance(key, dict):
+                key_name = key.get("name", key.get("id"))
+            else:
+                key_name = key
+
+            if key_name:
+                print(f"   Deleting key: {key_name}")
+                delete_result = make_request(f"/ssh-keys/{key_name}", method="DELETE")
+                if delete_result is not None:
+                    print(f"     ✓ Deleted {key_name}")
+                else:
+                    print(f"     ✗ Failed to delete {key_name}")
+    else:
+        print("   Response:", json.dumps(result, indent=2))
+else:
+    print("   ✗ SSH Keys endpoint failed")
+
+print("\n5. Testing if keys were deleted...")
+result = make_request("/ssh-keys")
+if result and "data" in result:
+    print(f"   Remaining keys: {len(result['data'])}")
diff --git a/scripts/update_lambdalabs_instance.sh b/scripts/update_lambdalabs_instance.sh
new file mode 100755
index 0000000..219e425
--- /dev/null
+++ b/scripts/update_lambdalabs_instance.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+echo "Lambda Labs Instance Availability Update"
+echo "========================================"
+echo
+echo "The configured instance type 'gpu_1x_a10' is currently unavailable."
+echo
+echo "Available options:"
+echo
+echo "1. Use gpu_1x_a100_sxm4 in us-east-1 (Virginia) - $1.29/hr"
+echo "   To use this, run:"
+echo "   make menuconfig"
+echo "   Then navigate to:"
+echo "   - Terraform -> Lambda Labs cloud provider"
+echo "   - Change 'Lambda Labs region' to 'us-east-1'"
+echo "   - Change 'Lambda Labs instance type' to 'gpu_1x_a100_sxm4'"
+echo
+echo "2. Use gpu_8x_a100 in us-west-1 (California) - $10.32/hr"
+echo "   To use this, run:"
+echo "   make menuconfig"
+echo "   Then navigate to:"
+echo "   - Terraform -> Lambda Labs cloud provider"
+echo "   - Change 'Lambda Labs instance type' to 'gpu_8x_a100'"
+echo
+echo "3. Wait for gpu_1x_a10 to become available"
+echo "   Check availability at: https://cloud.lambdalabs.com/"
+echo
+echo "Current configuration:"
+grep "CONFIG_TERRAFORM_LAMBDALABS_REGION\|CONFIG_TERRAFORM_LAMBDALABS_INSTANCE_TYPE" .config 2>/dev/null || echo "  Configuration not found"
-- 
2.50.1


  parent reply	other threads:[~2025-08-27 21:29 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-27 21:28 [PATCH v2 00/10] terraform: add Lambda Labs cloud provider support with dynamic API-driven configuration Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 01/10] gitignore: add entries for Lambda Labs dynamic configuration Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 02/10] scripts: add Lambda Labs Python API library Luis Chamberlain
2025-08-28 18:59   ` Chuck Lever
2025-08-28 19:33     ` Luis Chamberlain
2025-08-28 20:00       ` Chuck Lever
2025-08-28 20:03         ` Luis Chamberlain
2025-08-28 20:13           ` Chuck Lever
2025-08-28 20:16             ` Luis Chamberlain
2025-08-29 11:24               ` Luis Chamberlain
2025-08-29 13:48                 ` Chuck Lever
2025-08-27 21:28 ` [PATCH v2 03/10] scripts: add Lambda Labs credentials management Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 04/10] scripts: add Lambda Labs SSH key management utilities Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 05/10] kconfig: add dynamic cloud provider configuration infrastructure Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 06/10] terraform/lambdalabs: add Kconfig structure for Lambda Labs Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 07/10] terraform/lambdalabs: add terraform provider implementation Luis Chamberlain
2025-08-27 21:28 ` [PATCH v2 08/10] ansible/terraform: integrate Lambda Labs into build system Luis Chamberlain
2025-08-27 21:29 ` Luis Chamberlain [this message]
2025-08-27 21:29 ` [PATCH v2 10/10] terraform: enable Lambda Labs cloud provider in menus Luis Chamberlain

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250827212902.4021990-10-mcgrof@kernel.org \
    --to=mcgrof@kernel.org \
    --cc=cel@kernel.org \
    --cc=da.gomez@kruces.com \
    --cc=kdevops@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.