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>, Your Name <email@example.com>
Subject: [PATCH v3 02/10] scripts: add Lambda Labs Python API library
Date: Sat, 30 Aug 2025 20:59:56 -0700 [thread overview]
Message-ID: <20250831040004.2159779-3-mcgrof@kernel.org> (raw)
In-Reply-To: <20250831040004.2159779-1-mcgrof@kernel.org>
Add core Python API library for Lambda Labs cloud provider integration:
- Low-level API access with Bearer token authentication
- Instance types discovery with capacity information
- Regions extraction from instance data
- Dynamic Kconfig generation for instance types and regions
- Pricing data integration
- Proper error handling and fallback mechanisms
This provides the foundation for Lambda Labs cloud provider support
in kdevops, enabling dynamic configuration based on real-time
availability and pricing data.
Generated-by: Claude AI
Signed-off-by: Your Name <email@example.com>
---
scripts/lambdalabs_api.py | 556 ++++++++++++++++++++++++++++++++++++++
1 file changed, 556 insertions(+)
create mode 100755 scripts/lambdalabs_api.py
diff --git a/scripts/lambdalabs_api.py b/scripts/lambdalabs_api.py
new file mode 100755
index 0000000..b6d6814
--- /dev/null
+++ b/scripts/lambdalabs_api.py
@@ -0,0 +1,556 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: MIT
+
+"""
+Lambda Labs API library for kdevops.
+
+Provides low-level API access for Lambda Labs cloud services.
+Used by lambda-cli and other kdevops components.
+"""
+
+import json
+import os
+import sys
+import urllib.request
+import urllib.error
+from typing import Dict, List, Optional, Tuple
+
+# 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 make_api_request(endpoint: str, api_key: str) -> Optional[Dict]:
+ """Make a request to Lambda Labs API."""
+ url = f"{LAMBDALABS_API_BASE}{endpoint}"
+ headers = {
+ "Authorization": f"Bearer {api_key}",
+ "Content-Type": "application/json",
+ "User-Agent": "kdevops/1.0",
+ }
+
+ try:
+ req = urllib.request.Request(url, headers=headers)
+ with urllib.request.urlopen(req) as response:
+ return json.loads(response.read().decode())
+ except urllib.error.HTTPError as e:
+ print(f"HTTP Error {e.code}: {e.reason}", file=sys.stderr)
+ return None
+ except Exception as e:
+ print(f"Error making API request: {e}", file=sys.stderr)
+ return None
+
+
+def get_instance_types_with_capacity(api_key: str) -> Tuple[Dict, Dict[str, List[str]]]:
+ """
+ Get available instance types from Lambda Labs with capacity information.
+
+ Returns:
+ Tuple of (instance_types_data, capacity_map)
+ where capacity_map is {instance_type: [list of regions with capacity]}
+ """
+ response = make_api_request("/instance-types", api_key)
+ if not response or "data" not in response:
+ return {}, {}
+
+ instance_data = response["data"]
+ capacity_map = {}
+
+ # Build capacity map
+ for instance_type, info in instance_data.items():
+ regions_with_capacity = info.get("regions_with_capacity_available", [])
+ if regions_with_capacity:
+ capacity_map[instance_type] = [r["name"] for r in regions_with_capacity]
+ else:
+ capacity_map[instance_type] = []
+
+ return instance_data, capacity_map
+
+
+def get_regions(api_key: str) -> List[Dict]:
+ """Get available regions from Lambda Labs by extracting from instance data."""
+ # Lambda Labs doesn't have a dedicated regions endpoint
+ # Extract regions from instance-types data
+ response = make_api_request("/instance-types", api_key)
+ if response and "data" in response:
+ regions_set = set()
+ region_descriptions = {
+ "us-tx-1": "US Texas",
+ "us-midwest-1": "US Midwest",
+ "us-west-1": "US West (California)",
+ "us-west-2": "US West 2",
+ "us-west-3": "US West 3",
+ "us-south-1": "US South",
+ "europe-central-1": "Europe Central",
+ "asia-northeast-1": "Asia Northeast",
+ "asia-south-1": "Asia South",
+ "me-west-1": "Middle East West",
+ "us-east-1": "US East (Virginia)",
+ }
+
+ # Extract all regions from instance data
+ for instance_name, instance_info in response["data"].items():
+ regions_available = instance_info.get("regions_with_capacity_available", [])
+ for region in regions_available:
+ # Handle both string and dict formats
+ if isinstance(region, dict):
+ region_name = region.get("name", region.get("region", str(region)))
+ else:
+ region_name = str(region)
+ regions_set.add(region_name)
+
+ # Return as list of dicts to match expected format
+ return [
+ {
+ "name": region,
+ "description": region_descriptions.get(region, region.replace("-", " ").title())
+ }
+ for region in sorted(regions_set)
+ ]
+ return []
+
+
+def get_images(api_key: str) -> List[Dict]:
+ """Get available OS images from Lambda Labs."""
+ response = make_api_request("/images", api_key)
+ if response and "data" in response:
+ return response["data"]
+ return []
+
+
+def sanitize_kconfig_name(name: str) -> str:
+ """Convert a name to a valid Kconfig symbol."""
+ # Replace special characters with underscores
+ name = name.replace("-", "_").replace(".", "_").replace(" ", "_")
+ # Convert to uppercase
+ name = name.upper()
+ # Remove any non-alphanumeric characters (except underscore)
+ name = "".join(c for c in name if c.isalnum() or c == "_")
+ # Ensure it doesn't start with a number
+ if name and name[0].isdigit():
+ name = "_" + name
+ return name
+
+
+def get_instance_pricing() -> Dict[str, float]:
+ """Get hardcoded instance pricing data (per hour in USD).
+
+ Prices are based on Lambda Labs public pricing as of 2025.
+ These are on-demand prices; reserved instances may be cheaper.
+ """
+ return {
+ # 1x GPU instances
+ "gpu_1x_gh200": 1.49,
+ "gpu_1x_h100_sxm": 3.29,
+ "gpu_1x_h100_pcie": 2.49,
+ "gpu_1x_a100": 1.29,
+ "gpu_1x_a100_sxm": 1.29,
+ "gpu_1x_a100_pcie": 1.29,
+ "gpu_1x_a10": 0.75,
+ "gpu_1x_a6000": 0.80,
+ "gpu_1x_rtx6000": 0.50,
+ "gpu_1x_quadro_rtx_6000": 0.50,
+ # 2x GPU instances
+ "gpu_2x_h100_sxm": 6.38, # 2 * 3.19
+ "gpu_2x_a100": 2.58, # 2 * 1.29
+ "gpu_2x_a100_pcie": 2.58, # 2 * 1.29
+ "gpu_2x_a6000": 1.60, # 2 * 0.80
+ # 4x GPU instances
+ "gpu_4x_h100_sxm": 12.36, # 4 * 3.09
+ "gpu_4x_a100": 5.16, # 4 * 1.29
+ "gpu_4x_a100_pcie": 5.16, # 4 * 1.29
+ "gpu_4x_a6000": 3.20, # 4 * 0.80
+ # 8x GPU instances
+ "gpu_8x_b200_sxm": 39.92, # 8 * 4.99
+ "gpu_8x_h100_sxm": 23.92, # 8 * 2.99
+ "gpu_8x_a100_80gb": 14.32, # 8 * 1.79
+ "gpu_8x_a100_80gb_sxm": 14.32, # 8 * 1.79
+ "gpu_8x_a100": 10.32, # 8 * 1.29
+ "gpu_8x_a100_40gb": 10.32, # 8 * 1.29
+ "gpu_8x_v100": 4.40, # 8 * 0.55
+ }
+
+
+def generate_instance_types_kconfig(api_key: str) -> str:
+ """Generate Kconfig content for Lambda Labs instance types with capacity info."""
+ instance_types, capacity_map = get_instance_types_with_capacity(api_key)
+ pricing = get_instance_pricing()
+
+ if not instance_types:
+ # Fallback to some default instance types if API is unavailable
+ return """# Lambda Labs instance types (API unavailable - using defaults)
+
+choice
+ prompt "Lambda Labs instance type"
+ default TERRAFORM_LAMBDALABS_INSTANCE_TYPE_GPU_1X_A10
+ help
+ Select the Lambda Labs instance type for your deployment.
+ Note: API is currently unavailable, showing default options.
+ Prices shown are on-demand hourly rates in USD.
+
+config TERRAFORM_LAMBDALABS_INSTANCE_TYPE_GPU_1X_A10
+ bool "gpu_1x_a10 - 1x NVIDIA A10 GPU ($0.75/hr)"
+ help
+ Single NVIDIA A10 GPU instance with 24GB VRAM.
+ Price: $0.75 per hour (on-demand)
+
+config TERRAFORM_LAMBDALABS_INSTANCE_TYPE_GPU_1X_A100
+ bool "gpu_1x_a100 - 1x NVIDIA A100 GPU ($1.29/hr)"
+ help
+ Single NVIDIA A100 GPU instance with 40GB VRAM.
+ Price: $1.29 per hour (on-demand)
+
+config TERRAFORM_LAMBDALABS_INSTANCE_TYPE_GPU_8X_A100_80GB
+ bool "gpu_8x_a100_80gb - 8x NVIDIA A100 GPU ($14.32/hr)"
+ help
+ Eight NVIDIA A100 GPUs with 80GB VRAM each.
+ Price: $14.32 per hour (on-demand)
+
+endchoice
+"""
+
+ # Separate instance types by availability
+ available_types = []
+ unavailable_types = []
+
+ for name, info in instance_types.items():
+ if name in capacity_map and capacity_map[name]:
+ available_types.append((name, info))
+ else:
+ unavailable_types.append((name, info))
+
+ # Sort by name for consistency
+ available_types.sort(key=lambda x: x[0])
+ unavailable_types.sort(key=lambda x: x[0])
+
+ # Generate dynamic Kconfig from API data
+ kconfig = (
+ "# Lambda Labs instance types (dynamically generated with capacity info)\n\n"
+ )
+ kconfig += "choice\n"
+ kconfig += '\tprompt "Lambda Labs instance type"\n'
+
+ # Use the first available instance type as default
+ if available_types:
+ default_type = sanitize_kconfig_name(available_types[0][0])
+ kconfig += f"\tdefault TERRAFORM_LAMBDALABS_INSTANCE_TYPE_{default_type}\n"
+
+ kconfig += "\thelp\n"
+ kconfig += "\t Select the Lambda Labs instance type for your deployment.\n"
+ kconfig += "\t These options are dynamically generated from the Lambda Labs API.\n"
+ kconfig += "\t [Available] = Has capacity in at least one region\n"
+ kconfig += "\t [No Capacity] = Currently no capacity available\n"
+ kconfig += "\t Prices shown are on-demand hourly rates in USD.\n\n"
+
+ # First add available instance types
+ if available_types:
+ kconfig += "# Instance types WITH available capacity:\n"
+ for name, info in available_types:
+ kconfig_name = sanitize_kconfig_name(name)
+
+ # Get instance details
+ instance_info = info.get("instance_type", {})
+ description = instance_info.get("description", name)
+
+ # Get pricing for this instance type
+ price = pricing.get(name, 0)
+ price_str = f"${price:.2f}/hr" if price > 0 else "Price N/A"
+
+ # Get capacity regions
+ regions = capacity_map.get(name, [])
+ regions_str = ", ".join(regions[:3]) # Show first 3 regions
+ if len(regions) > 3:
+ regions_str += f" +{len(regions)-3} more"
+
+ # Get instance specifications
+ specs = instance_info.get("specs", {})
+ vcpus = specs.get("vcpus", "N/A")
+ memory_gib = specs.get("memory_gib", "N/A")
+ storage_gib = specs.get("storage_gib", "N/A")
+
+ kconfig += f"config TERRAFORM_LAMBDALABS_INSTANCE_TYPE_{kconfig_name}\n"
+ kconfig += f'\tbool "{name} ({price_str}) - {description} [AVAILABLE]"\n'
+ kconfig += "\thelp\n"
+ kconfig += f"\t {description}\n"
+ kconfig += f"\t AVAILABLE in: {regions_str}\n"
+ kconfig += f"\t Price: {price_str} (on-demand)\n"
+ kconfig += f"\t vCPUs: {vcpus}, Memory: {memory_gib} GiB, Storage: {storage_gib} GiB\n\n"
+
+ # Then add unavailable instance types (commented out or with warning)
+ if unavailable_types:
+ kconfig += "# Instance types WITHOUT capacity (not recommended):\n"
+ for name, info in unavailable_types:
+ kconfig_name = sanitize_kconfig_name(name)
+
+ # Get instance details
+ instance_info = info.get("instance_type", {})
+ description = instance_info.get("description", name)
+
+ # Get pricing for this instance type
+ price = pricing.get(name, 0)
+ price_str = f"${price:.2f}/hr" if price > 0 else "Price N/A"
+
+ kconfig += f"config TERRAFORM_LAMBDALABS_INSTANCE_TYPE_{kconfig_name}\n"
+ kconfig += f'\tbool "{name} ({price_str}) - [NO CAPACITY]"\n'
+ kconfig += "\thelp\n"
+ kconfig += f"\t {description}\n"
+ kconfig += f"\t WARNING: Currently NO CAPACITY in any region!\n"
+ kconfig += f"\t This option will fail during provisioning.\n"
+ kconfig += f"\t Price: {price_str} (on-demand) when available\n\n"
+
+ kconfig += "endchoice\n"
+
+ # Don't generate the TERRAFORM_LAMBDALABS_INSTANCE_TYPE config here
+ # It's already defined in Kconfig.compute with proper defaults
+
+ return kconfig
+
+
+def generate_instance_type_mappings(api_key: str) -> str:
+ """Generate Kconfig mappings for all instance types."""
+ instance_types, _ = get_instance_types_with_capacity(api_key)
+
+ # Generate mappings for TERRAFORM_LAMBDALABS_INSTANCE_TYPE config
+ mappings = []
+ for name in sorted(instance_types.keys()):
+ kconfig_name = sanitize_kconfig_name(name)
+ mappings.append(f'\tdefault "{name}" if TERRAFORM_LAMBDALABS_INSTANCE_TYPE_{kconfig_name}')
+
+ return '\n'.join(mappings)
+
+
+def generate_regions_kconfig(api_key: str) -> str:
+ """Generate Kconfig content for Lambda Labs regions with capacity indicators."""
+ regions = get_regions(api_key)
+
+ # Get capacity information
+ _, capacity_map = get_instance_types_with_capacity(api_key)
+
+ # Count how many instance types have capacity in each region
+ region_capacity_count = {}
+ for instance_type, available_regions in capacity_map.items():
+ for region in available_regions:
+ region_capacity_count[region] = region_capacity_count.get(region, 0) + 1
+
+ if not regions:
+ # Fallback to default regions if API is unavailable
+ return """# Lambda Labs regions (API unavailable - using defaults)
+
+choice
+ prompt "Lambda Labs region"
+ default TERRAFORM_LAMBDALABS_REGION_US_TX_1
+ help
+ Select the Lambda Labs region for deployment.
+ Note: API is currently unavailable, showing default options.
+
+config TERRAFORM_LAMBDALABS_REGION_US_TX_1
+ bool "us-tx-1 - Texas, USA"
+
+config TERRAFORM_LAMBDALABS_REGION_US_MIDWEST_1
+ bool "us-midwest-1 - Midwest, USA"
+
+config TERRAFORM_LAMBDALABS_REGION_US_WEST_1
+ bool "us-west-1 - West Coast, USA"
+
+endchoice
+"""
+
+ # Sort regions by capacity count (most capacity first)
+ regions_sorted = sorted(
+ regions,
+ key=lambda r: region_capacity_count.get(r.get("name", ""), 0),
+ reverse=True,
+ )
+
+ # Generate dynamic Kconfig from API data
+ kconfig = "# Lambda Labs regions (dynamically generated with capacity info)\n\n"
+ kconfig += "choice\n"
+ kconfig += '\tprompt "Lambda Labs region"\n'
+
+ # Use region with most capacity as default
+ if regions_sorted:
+ default_region = sanitize_kconfig_name(regions_sorted[0].get("name", "us_tx_1"))
+ kconfig += f"\tdefault TERRAFORM_LAMBDALABS_REGION_{default_region}\n"
+
+ kconfig += "\thelp\n"
+ kconfig += "\t Select the Lambda Labs region for deployment.\n"
+ kconfig += (
+ "\t Number shows how many instance types have capacity in that region.\n"
+ )
+ kconfig += "\t Choose regions with higher numbers for better availability.\n\n"
+
+ for region in regions_sorted:
+ name = region.get("name", "")
+ if not name:
+ continue
+
+ kconfig_name = sanitize_kconfig_name(name)
+ description = region.get("description", name)
+
+ # Get capacity count for this region
+ capacity_count = region_capacity_count.get(name, 0)
+
+ if capacity_count > 0:
+ capacity_str = f"[{capacity_count} types available]"
+ else:
+ capacity_str = "[NO CAPACITY]"
+
+ kconfig += f"config TERRAFORM_LAMBDALABS_REGION_{kconfig_name}\n"
+ kconfig += f'\tbool "{name} - {description} {capacity_str}"\n'
+ kconfig += "\thelp\n"
+ kconfig += f"\t Region: {description}\n"
+ if capacity_count > 0:
+ kconfig += (
+ f"\t {capacity_count} instance types have capacity in this region.\n\n"
+ )
+ else:
+ kconfig += "\t WARNING: No instance types currently have capacity in this region!\n\n"
+
+ kconfig += "endchoice\n"
+
+ # Don't generate the TERRAFORM_LAMBDALABS_REGION config here
+ # It's already defined in Kconfig.location with proper defaults
+
+ return kconfig
+
+
+def generate_images_kconfig(api_key: str) -> str:
+ """Generate Kconfig content for Lambda Labs OS images."""
+ images = get_images(api_key)
+
+ if not images:
+ # Note: Lambda Labs doesn't support OS selection via terraform
+ return """# Lambda Labs OS images configuration
+
+# NOTE: The Lambda Labs terraform provider (elct9620/lambdalabs v0.3.0) does NOT support
+# OS image selection. Lambda Labs automatically deploys Ubuntu 22.04 LTS by default.
+#
+# The provider only supports these attributes for instances:
+# - name (instance name)
+# - region_name (deployment region)
+# - instance_type_name (GPU type)
+# - ssh_key_names (SSH keys)
+#
+# What's NOT supported:
+# - OS/distribution selection
+# - Custom user creation
+# - User data/cloud-init scripts
+# - Storage configuration
+#
+# SSH User: Always "ubuntu" (the OS default user)
+#
+# This file is kept as a placeholder for future provider updates.
+
+# No configuration options available - provider doesn't support OS selection
+"""
+
+ # If we somehow get images from API (future), generate the config
+ # but add a warning that it's not supported by terraform provider
+ kconfig = (
+ "# Lambda Labs OS images (from API but NOT SUPPORTED by terraform provider)\n\n"
+ )
+ kconfig += "# WARNING: The terraform provider does NOT support OS selection!\n"
+ kconfig += "# These options are shown for reference only.\n\n"
+
+ kconfig += "choice\n"
+ kconfig += '\tprompt "Lambda Labs OS image (NOT SUPPORTED)"\n'
+
+ # Use first available image as default
+ if images:
+ default_image = sanitize_kconfig_name(images[0].get("name", "ubuntu_22_04"))
+ kconfig += f"\tdefault TERRAFORM_LAMBDALABS_IMAGE_{default_image}\n"
+
+ kconfig += "\thelp\n"
+ kconfig += "\t WARNING: OS selection is NOT supported by the terraform provider.\n"
+ kconfig += "\t Lambda Labs will always deploy Ubuntu 22.04 regardless of this setting.\n\n"
+
+ for image in images:
+ name = image.get("name", "")
+ if not name:
+ continue
+
+ kconfig_name = sanitize_kconfig_name(name)
+ description = image.get("description", name)
+
+ kconfig += f"config TERRAFORM_LAMBDALABS_IMAGE_{kconfig_name}\n"
+ kconfig += f'\tbool "{description} (NOT SUPPORTED)"\n\n'
+
+ kconfig += "endchoice\n\n"
+
+ # Generate the string config that maps choices to actual values
+ kconfig += "config TERRAFORM_LAMBDALABS_IMAGE\n"
+ kconfig += "\tstring\n"
+ kconfig += "\toutput yaml\n"
+
+ for image in images:
+ name = image.get("name", "")
+ if not name:
+ continue
+ kconfig_name = sanitize_kconfig_name(name)
+ kconfig += f'\tdefault "{name}" if TERRAFORM_LAMBDALABS_IMAGE_{kconfig_name}\n'
+
+ return kconfig
+
+
+def main():
+ """Main entry point for generating Lambda Labs Kconfig files."""
+ if len(sys.argv) < 2:
+ print("Usage: lambdalabs_api.py <command> [args...]")
+ print("Commands:")
+ print(" instance-types - Generate instance types Kconfig")
+ print(" regions - Generate regions Kconfig")
+ print(" images - Generate OS images Kconfig")
+ print(" all - Generate all Kconfig files")
+ sys.exit(1)
+
+ command = sys.argv[1]
+ api_key = get_api_key()
+
+ if not api_key:
+ print(
+ "Warning: Lambda Labs API key not found, using default values",
+ file=sys.stderr,
+ )
+ api_key = "" # Will trigger fallback behavior
+
+ if command == "instance-types":
+ print(generate_instance_types_kconfig(api_key))
+ elif command == "regions":
+ print(generate_regions_kconfig(api_key))
+ elif command == "images":
+ print(generate_images_kconfig(api_key))
+ elif command == "all":
+ # Generate all Kconfig files
+ output_dir = (
+ sys.argv[2] if len(sys.argv) > 2 else "terraform/lambdalabs/kconfigs"
+ )
+
+ os.makedirs(output_dir, exist_ok=True)
+
+ # Generate instance types
+ with open(os.path.join(output_dir, "Kconfig.compute.generated"), "w") as f:
+ f.write(generate_instance_types_kconfig(api_key))
+
+ # Generate regions
+ with open(os.path.join(output_dir, "Kconfig.location.generated"), "w") as f:
+ f.write(generate_regions_kconfig(api_key))
+
+ # Generate images
+ with open(os.path.join(output_dir, "Kconfig.images.generated"), "w") as f:
+ f.write(generate_images_kconfig(api_key))
+
+ print(f"Generated Kconfig files in {output_dir}")
+ else:
+ print(f"Unknown command: {command}", file=sys.stderr)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
--
2.50.1
next prev parent reply other threads:[~2025-08-31 4:00 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-31 3:59 [PATCH v3 00/10] terraform: add Lambda Labs cloud provider support Luis Chamberlain
2025-08-31 3:59 ` [PATCH v3 01/10] gitignore: add entries for Lambda Labs dynamic configuration Luis Chamberlain
2025-08-31 3:59 ` Luis Chamberlain [this message]
2025-08-31 3:59 ` [PATCH v3 03/10] scripts: add Lambda Labs testing and debugging utilities Luis Chamberlain
2025-08-31 3:59 ` [PATCH v3 04/10] scripts: add Lambda Labs credentials management Luis Chamberlain
2025-08-31 3:59 ` [PATCH v3 05/10] scripts: add Lambda Labs SSH key management utilities Luis Chamberlain
2025-08-31 4:00 ` [PATCH v3 06/10] kconfig: add dynamic cloud provider configuration infrastructure Luis Chamberlain
2025-08-31 4:00 ` [PATCH v3 07/10] terraform/lambdalabs: add Kconfig structure for Lambda Labs Luis Chamberlain
2025-08-31 4:00 ` [PATCH v3 08/10] terraform/lambdalabs: add terraform provider implementation Luis Chamberlain
2025-08-31 4:00 ` [PATCH v3 09/10] ansible/terraform: integrate Lambda Labs into build system Luis Chamberlain
2025-08-31 4:00 ` [PATCH v3 10/10] kconfigs: enable Lambda Labs cloud provider in menus Luis Chamberlain
2025-09-01 1:10 ` [PATCH v3 00/10] terraform: add Lambda Labs cloud provider support 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=20250831040004.2159779-3-mcgrof@kernel.org \
--to=mcgrof@kernel.org \
--cc=cel@kernel.org \
--cc=da.gomez@kruces.com \
--cc=email@example.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox