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 05/10] scripts: add Lambda Labs SSH key management utilities
Date: Sat, 30 Aug 2025 20:59:59 -0700 [thread overview]
Message-ID: <20250831040004.2159779-6-mcgrof@kernel.org> (raw)
In-Reply-To: <20250831040004.2159779-1-mcgrof@kernel.org>
Add comprehensive SSH key management for Lambda Labs:
- lambdalabs_ssh_keys.py: Core SSH key operations (list, upload, delete)
- lambdalabs_ssh_key_name.py: Smart SSH key name resolution
- ssh_config_file_name.py: SSH config filename inference
- update_ssh_config_lambdalabs.py: Automatic SSH configuration
Features:
- Automatic local SSH key discovery and upload
- Smart name generation from key content and hostnames
- SSH config file management for seamless connectivity
- Integration with kdevops SSH workflow patterns
These utilities enable seamless SSH key provisioning and management
for Lambda Labs instances.
Generated-by: Claude AI
Signed-off-by: Your Name <email@example.com>
---
scripts/lambdalabs_ssh_key_name.py | 135 +++++++++
scripts/lambdalabs_ssh_keys.py | 358 ++++++++++++++++++++++++
scripts/ssh_config_file_name.py | 79 ++++++
scripts/update_ssh_config_lambdalabs.py | 110 ++++++++
4 files changed, 682 insertions(+)
create mode 100755 scripts/lambdalabs_ssh_key_name.py
create mode 100755 scripts/lambdalabs_ssh_keys.py
create mode 100755 scripts/ssh_config_file_name.py
create mode 100755 scripts/update_ssh_config_lambdalabs.py
diff --git a/scripts/lambdalabs_ssh_key_name.py b/scripts/lambdalabs_ssh_key_name.py
new file mode 100755
index 0000000..131ac3a
--- /dev/null
+++ b/scripts/lambdalabs_ssh_key_name.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Generate a unique SSH key name for Lambda Labs based on the current directory.
+This ensures each kdevops instance uses its own SSH key for security.
+"""
+
+import hashlib
+import os
+import sys
+
+
+def get_directory_hash(path: str, length: int = 8) -> str:
+ """
+ Generate a short hash of the directory path.
+
+ Args:
+ path: Directory path to hash
+ length: Number of hex characters to use (default 8)
+
+ Returns:
+ Hex string of specified length
+ """
+ # Get the absolute path to ensure consistency
+ abs_path = os.path.abspath(path)
+
+ # Create SHA256 hash of the path
+ hash_obj = hashlib.sha256(abs_path.encode("utf-8"))
+
+ # Return first N characters of the hex digest
+ return hash_obj.hexdigest()[:length]
+
+
+def get_project_name(path: str) -> str:
+ """
+ Extract a meaningful project name from the path.
+
+ Args:
+ path: Directory path
+
+ Returns:
+ Project name derived from directory
+ """
+ abs_path = os.path.abspath(path)
+
+ # Get the last two directory components for context
+ # e.g., /home/user/projects/kdevops -> projects-kdevops
+ parts = abs_path.rstrip("/").split("/")
+
+ if len(parts) >= 2:
+ # Use last two directories
+ project_parts = parts[-2:]
+ # Filter out generic names
+ filtered = [
+ p
+ for p in project_parts
+ if p not in ["data", "home", "root", "usr", "var", "tmp"]
+ ]
+ if filtered:
+ return "-".join(filtered)
+
+ # Fallback to just the last directory
+ return parts[-1] if parts else "kdevops"
+
+
+def generate_ssh_key_name(prefix: str = "kdevops", include_project: bool = True) -> str:
+ """
+ Generate a unique SSH key name for the current directory.
+
+ Args:
+ prefix: Prefix for the key name (default "kdevops")
+ include_project: Include project name in the key (default True)
+
+ Returns:
+ Unique SSH key name like "kdevops-lambda-kdevops-a1b2c3d4"
+ """
+ cwd = os.getcwd()
+ dir_hash = get_directory_hash(cwd)
+
+ parts = [prefix]
+
+ if include_project:
+ project = get_project_name(cwd)
+ # Limit project name length and sanitize
+ project = project.replace("_", "-").replace(".", "-")[:20]
+ parts.append(project)
+
+ parts.append(dir_hash)
+
+ # Create the key name
+ key_name = "-".join(parts)
+
+ # Ensure it's a valid name (alphanumeric and hyphens only)
+ key_name = "".join(c if c.isalnum() or c == "-" else "-" for c in key_name)
+
+ # Remove multiple consecutive hyphens
+ while "--" in key_name:
+ key_name = key_name.replace("--", "-")
+
+ # Trim to reasonable length (Lambda Labs might have limits)
+ if len(key_name) > 50:
+ # Keep prefix, partial project, and full hash
+ key_name = f"{prefix}-{dir_hash}"
+
+ return key_name.strip("-")
+
+
+def main():
+ """Main entry point."""
+ if len(sys.argv) > 1:
+ if sys.argv[1] == "--help" or sys.argv[1] == "-h":
+ print("Usage: lambdalabs_ssh_key_name.py [--simple]")
+ print()
+ print("Generate a unique SSH key name based on current directory.")
+ print()
+ print("Options:")
+ print(" --simple Generate simple name without project context")
+ print(" --help Show this help message")
+ print()
+ print("Examples:")
+ print(" Default: kdevops-lambda-kdevops-a1b2c3d4")
+ print(" Simple: kdevops-a1b2c3d4")
+ sys.exit(0)
+ elif sys.argv[1] == "--simple":
+ print(generate_ssh_key_name(include_project=False))
+ else:
+ print(f"Unknown option: {sys.argv[1]}", file=sys.stderr)
+ sys.exit(1)
+ else:
+ print(generate_ssh_key_name())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/lambdalabs_ssh_keys.py b/scripts/lambdalabs_ssh_keys.py
new file mode 100755
index 0000000..2fa9880
--- /dev/null
+++ b/scripts/lambdalabs_ssh_keys.py
@@ -0,0 +1,358 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Lambda Labs SSH Key Management via API.
+Provides functions to list, add, and delete SSH keys through the Lambda Labs API.
+"""
+
+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, method: str = "GET", data: Optional[Dict] = None
+) -> 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_data = None
+ if data and method in ["POST", "PUT", "PATCH"]:
+ req_data = json.dumps(data).encode("utf-8")
+
+ req = urllib.request.Request(url, headers=headers, data=req_data, method=method)
+ 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)
+ if e.code == 404:
+ print(f"Endpoint not found: {endpoint}", file=sys.stderr)
+ try:
+ error_body = e.read().decode()
+ print(f"Error details: {error_body}", file=sys.stderr)
+ except:
+ pass
+ return None
+ except Exception as e:
+ print(f"Error making API request: {e}", file=sys.stderr)
+ return None
+
+
+def list_ssh_keys(api_key: str) -> Optional[List[Dict]]:
+ """
+ List all SSH keys associated with the Lambda Labs account.
+
+ Returns:
+ List of SSH key dictionaries with 'name', 'id', and 'public_key' fields
+ """
+ response = make_api_request("/ssh-keys", api_key)
+ if response:
+ # The API returns {"data": [{name, id, public_key}, ...]}
+ if "data" in response:
+ return response["data"]
+ # Fallback for other response formats
+ elif isinstance(response, list):
+ return response
+ return None
+
+
+def add_ssh_key(api_key: str, name: str, public_key: str) -> bool:
+ """
+ Add a new SSH key to the Lambda Labs account.
+
+ Args:
+ api_key: Lambda Labs API key
+ name: Name for the SSH key
+ public_key: The public key content
+
+ Returns:
+ True if successful, False otherwise
+ """
+ # Based on the API response structure, the endpoint is /ssh-keys
+ # and the format is likely {"name": name, "public_key": public_key}
+ endpoint = "/ssh-keys"
+ data = {"name": name, "public_key": public_key.strip()}
+
+ print(f"Adding SSH key '{name}' via POST {endpoint}", file=sys.stderr)
+ response = make_api_request(endpoint, api_key, method="POST", data=data)
+ if response:
+ print(f"Successfully added SSH key '{name}'", file=sys.stderr)
+ return True
+
+ # Try alternative format if the first one fails
+ data = {"name": name, "key": public_key.strip()}
+ print(f"Trying alternative format with 'key' field", file=sys.stderr)
+ response = make_api_request(endpoint, api_key, method="POST", data=data)
+ if response:
+ print(f"Successfully added SSH key '{name}'", file=sys.stderr)
+ return True
+
+ return False
+
+
+def delete_ssh_key(api_key: str, key_name_or_id: str) -> bool:
+ """
+ Delete an SSH key from the Lambda Labs account.
+
+ Args:
+ api_key: Lambda Labs API key
+ key_name_or_id: Name or ID of the SSH key to delete
+
+ Returns:
+ True if successful, False otherwise
+ """
+ # Check if input looks like an ID (32 character hex string)
+ is_id = len(key_name_or_id) == 32 and all(
+ c in "0123456789abcdef" for c in key_name_or_id.lower()
+ )
+
+ if not is_id:
+ # If we have a name, we need to find the ID
+ keys = list_ssh_keys(api_key)
+ if keys:
+ for key in keys:
+ if key.get("name") == key_name_or_id:
+ key_id = key.get("id")
+ if key_id:
+ print(
+ f"Found ID {key_id} for key '{key_name_or_id}'",
+ file=sys.stderr,
+ )
+ key_name_or_id = key_id
+ break
+ else:
+ print(f"SSH key '{key_name_or_id}' not found", file=sys.stderr)
+ return False
+
+ # Delete using the ID
+ endpoint = f"/ssh-keys/{key_name_or_id}"
+ print(f"Deleting SSH key via DELETE {endpoint}", file=sys.stderr)
+ response = make_api_request(endpoint, api_key, method="DELETE")
+ if response is not None:
+ print(f"Successfully deleted SSH key", file=sys.stderr)
+ return True
+
+ return False
+
+
+def read_public_key_file(filepath: str) -> Optional[str]:
+ """Read SSH public key from file."""
+ expanded_path = os.path.expanduser(filepath)
+ if not os.path.exists(expanded_path):
+ print(f"SSH public key file not found: {expanded_path}", file=sys.stderr)
+ return None
+
+ try:
+ with open(expanded_path, "r") as f:
+ return f.read().strip()
+ except Exception as e:
+ print(f"Error reading SSH public key: {e}", file=sys.stderr)
+ return None
+
+
+def check_ssh_key_exists(api_key: str, key_name: str) -> bool:
+ """
+ Check if an SSH key with the given name exists.
+
+ Args:
+ api_key: Lambda Labs API key
+ key_name: Name of the SSH key to check
+
+ Returns:
+ True if key exists, False otherwise
+ """
+ keys = list_ssh_keys(api_key)
+ if not keys:
+ return False
+
+ for key in keys:
+ # Try different possible field names
+ if key.get("name") == key_name or key.get("key_name") == key_name:
+ return True
+
+ return False
+
+
+def validate_ssh_setup(
+ api_key: str, expected_key_name: str = "kdevops-lambdalabs"
+) -> Tuple[bool, str]:
+ """
+ Validate that SSH keys are properly configured for Lambda Labs.
+
+ Args:
+ api_key: Lambda Labs API key
+ expected_key_name: The SSH key name we expect to use
+
+ Returns:
+ Tuple of (success, message)
+ """
+ # First, try to list SSH keys
+ keys = list_ssh_keys(api_key)
+
+ if keys is None:
+ # API doesn't support SSH key management
+ return (
+ False,
+ "Lambda Labs API does not appear to support SSH key management.\n"
+ "You must manually add your SSH key through the Lambda Labs web console:\n"
+ "1. Go to https://cloud.lambdalabs.com/ssh-keys\n"
+ "2. Click 'Add SSH key'\n"
+ f"3. Name it '{expected_key_name}'\n"
+ "4. Paste your public key from ~/.ssh/kdevops_terraform.pub",
+ )
+
+ if not keys:
+ # No keys found
+ return (
+ False,
+ "No SSH keys found in your Lambda Labs account.\n"
+ "Please add an SSH key through the web console or API before proceeding.",
+ )
+
+ # Check if expected key exists
+ key_names = []
+ for key in keys:
+ name = key.get("name") or key.get("key_name")
+ if name:
+ key_names.append(name)
+ if name == expected_key_name:
+ return (True, f"SSH key '{expected_key_name}' found and ready to use.")
+
+ # Key not found but other keys exist
+ key_list = "\n - ".join(key_names)
+ return (
+ False,
+ f"SSH key '{expected_key_name}' not found in your Lambda Labs account.\n"
+ f"Available SSH keys:\n - {key_list}\n"
+ f"Either:\n"
+ f"1. Add a key named '{expected_key_name}' through the web console\n"
+ f"2. Or update terraform/lambdalabs/kconfigs/Kconfig.identity to use one of the existing keys",
+ )
+
+
+def main():
+ """Main entry point for SSH key management."""
+ if len(sys.argv) < 2:
+ print("Usage: lambdalabs_ssh_keys.py <command> [args...]")
+ print("Commands:")
+ print(" list - List all SSH keys")
+ print(" check <name> - Check if a specific key exists")
+ print(" add <name> <public_key_file> - Add a new SSH key")
+ print(" delete <name> - Delete an SSH key")
+ print(" validate [key_name] - Validate SSH setup for kdevops")
+ sys.exit(1)
+
+ command = sys.argv[1]
+ api_key = get_api_key()
+
+ if not api_key:
+ print("Error: Lambda Labs API key not found", file=sys.stderr)
+ print("Please configure your API key:", file=sys.stderr)
+ print(
+ " python3 scripts/lambdalabs_credentials.py set 'your-api-key'",
+ file=sys.stderr,
+ )
+ sys.exit(1)
+
+ if command == "list":
+ keys = list_ssh_keys(api_key)
+ if keys is None:
+ print("Failed to list SSH keys - API may not support this feature")
+ sys.exit(1)
+ elif not keys:
+ print("No SSH keys found")
+ else:
+ print("SSH Keys:")
+ for key in keys:
+ if isinstance(key, dict):
+ name = key.get("name") or key.get("key_name") or "Unknown"
+ key_id = key.get("id", "")
+ fingerprint = key.get("fingerprint", "")
+ print(f" - Name: {name}")
+ if key_id and key_id != name:
+ print(f" ID: {key_id}")
+ if fingerprint:
+ print(f" Fingerprint: {fingerprint}")
+ # Show all fields for debugging
+ for k, v in key.items():
+ if k not in ["name", "id", "fingerprint", "key_name"]:
+ print(f" {k}: {v}")
+ else:
+ # Key is just a string (name)
+ print(f" - {key}")
+
+ elif command == "check":
+ if len(sys.argv) < 3:
+ print("Usage: lambdalabs_ssh_keys.py check <key_name>")
+ sys.exit(1)
+ key_name = sys.argv[2]
+ if check_ssh_key_exists(api_key, key_name):
+ print(f"SSH key '{key_name}' exists")
+ else:
+ print(f"SSH key '{key_name}' not found")
+ sys.exit(1)
+
+ elif command == "add":
+ if len(sys.argv) < 4:
+ print("Usage: lambdalabs_ssh_keys.py add <name> <public_key_file>")
+ sys.exit(1)
+ name = sys.argv[2]
+ key_file = sys.argv[3]
+
+ public_key = read_public_key_file(key_file)
+ if not public_key:
+ sys.exit(1)
+
+ if add_ssh_key(api_key, name, public_key):
+ print(f"Successfully added SSH key '{name}'")
+ else:
+ print(f"Failed to add SSH key '{name}'")
+ sys.exit(1)
+
+ elif command == "delete":
+ if len(sys.argv) < 3:
+ print("Usage: lambdalabs_ssh_keys.py delete <key_name>")
+ sys.exit(1)
+ key_name = sys.argv[2]
+
+ if delete_ssh_key(api_key, key_name):
+ print(f"Successfully deleted SSH key '{key_name}'")
+ else:
+ print(f"Failed to delete SSH key '{key_name}'")
+ sys.exit(1)
+
+ elif command == "validate":
+ key_name = sys.argv[2] if len(sys.argv) > 2 else "kdevops-lambdalabs"
+ success, message = validate_ssh_setup(api_key, key_name)
+ print(message)
+ if not success:
+ sys.exit(1)
+
+ else:
+ print(f"Unknown command: {command}", file=sys.stderr)
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/ssh_config_file_name.py b/scripts/ssh_config_file_name.py
new file mode 100755
index 0000000..9363548
--- /dev/null
+++ b/scripts/ssh_config_file_name.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+
+"""
+Generate a unique SSH config file name based on the current directory.
+This ensures each kdevops instance uses its own SSH config file.
+"""
+
+import hashlib
+import os
+import sys
+
+
+def get_directory_hash(path: str, length: int = 8) -> str:
+ """
+ Generate a short hash of the directory path.
+
+ Args:
+ path: Directory path to hash
+ length: Number of hex characters to use (default 8)
+
+ Returns:
+ Hex string of specified length
+ """
+ # Get the absolute path to ensure consistency
+ abs_path = os.path.abspath(path)
+
+ # Create SHA256 hash of the path
+ hash_obj = hashlib.sha256(abs_path.encode("utf-8"))
+
+ # Return first N characters of the hex digest
+ return hash_obj.hexdigest()[:length]
+
+
+def generate_ssh_config_filename(base_path: str = "~/.ssh/config_kdevops") -> str:
+ """
+ Generate a unique SSH config filename for the current directory.
+
+ Args:
+ base_path: Base path for the SSH config file (default ~/.ssh/config_kdevops)
+
+ Returns:
+ Unique SSH config filename like "~/.ssh/config_kdevops_a1b2c3d4"
+ """
+ cwd = os.getcwd()
+ dir_hash = get_directory_hash(cwd)
+
+ # Create the unique filename
+ config_file = f"{base_path}_{dir_hash}"
+
+ return config_file
+
+
+def main():
+ """Main entry point."""
+ if len(sys.argv) > 1:
+ if sys.argv[1] == "--help" or sys.argv[1] == "-h":
+ print("Usage: ssh_config_file_name.py [base_path]")
+ print()
+ print("Generate a unique SSH config filename based on current directory.")
+ print()
+ print("Options:")
+ print(
+ " base_path Base path for SSH config (default: ~/.ssh/config_kdevops)"
+ )
+ print()
+ print("Examples:")
+ print(" Default: ~/.ssh/config_kdevops_a1b2c3d4")
+ print(" Custom: /tmp/ssh_config_a1b2c3d4")
+ sys.exit(0)
+ else:
+ # Use provided base path
+ print(generate_ssh_config_filename(sys.argv[1]))
+ else:
+ print(generate_ssh_config_filename())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/update_ssh_config_lambdalabs.py b/scripts/update_ssh_config_lambdalabs.py
new file mode 100755
index 0000000..f944465
--- /dev/null
+++ b/scripts/update_ssh_config_lambdalabs.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: copyleft-next-0.3.1
+"""
+Update SSH config for Lambda Labs instances.
+Creates/updates SSH config entries for Lambda Labs cloud instances.
+"""
+
+import sys
+import os
+from pathlib import Path
+
+
+def update_ssh_config(action, hostname, ip_address, username, config_file, ssh_key, provider_name):
+ """
+ Update SSH configuration file with Lambda Labs instance details.
+
+ Args:
+ action: 'update' or 'remove'
+ hostname: Instance hostname
+ ip_address: Instance IP address
+ username: SSH username (usually 'ubuntu')
+ config_file: SSH config file path
+ ssh_key: Path to SSH private key
+ provider_name: Provider name for comments
+ """
+ config_file = os.path.expanduser(config_file)
+ ssh_key = os.path.expanduser(ssh_key)
+
+ # SSH config template for Lambda Labs
+ ssh_template = f"""# {provider_name} instance
+Host {hostname} {ip_address}
+\tHostName {ip_address}
+\tUser {username}
+\tPort 22
+\tIdentityFile {ssh_key}
+\tUserKnownHostsFile /dev/null
+\tStrictHostKeyChecking no
+\tPasswordAuthentication no
+\tIdentitiesOnly yes
+\tLogLevel FATAL
+"""
+
+ if action == "update":
+ # Remove existing entry if present
+ remove_from_config(hostname, config_file)
+
+ # Add new entry
+ with open(config_file, 'a') as f:
+ f.write(ssh_template)
+ print(f"✓ Updated SSH config for {hostname} ({ip_address}) in {config_file}")
+
+ elif action == "remove":
+ remove_from_config(hostname, config_file)
+ print(f"✓ Removed SSH config for {hostname} from {config_file}")
+
+ else:
+ print(f"Unknown action: {action}", file=sys.stderr)
+ sys.exit(1)
+
+
+def remove_from_config(hostname, config_file):
+ """Remove an entry from SSH config file."""
+ if not os.path.exists(config_file):
+ return
+
+ with open(config_file, 'r') as f:
+ lines = f.readlines()
+
+ # Find and remove the host block
+ new_lines = []
+ skip = False
+ for line in lines:
+ if line.startswith(f"Host {hostname} ") or line.startswith(f"Host {hostname}\t"):
+ skip = True
+ elif skip and line.startswith("Host "):
+ skip = False
+
+ if not skip:
+ new_lines.append(line)
+
+ with open(config_file, 'w') as f:
+ f.writelines(new_lines)
+
+
+def main():
+ """Main entry point."""
+ if len(sys.argv) < 7:
+ print(f"Usage: {sys.argv[0]} <action> <hostname> <ip_address> <username> <config_file> <ssh_key> [provider_name]")
+ print(" action: 'update' or 'remove'")
+ print(" hostname: Instance hostname")
+ print(" ip_address: Instance IP address")
+ print(" username: SSH username")
+ print(" config_file: SSH config file path")
+ print(" ssh_key: Path to SSH private key")
+ print(" provider_name: Optional provider name (default: 'Lambda Labs')")
+ sys.exit(1)
+
+ action = sys.argv[1]
+ hostname = sys.argv[2]
+ ip_address = sys.argv[3]
+ username = sys.argv[4]
+ config_file = sys.argv[5]
+ ssh_key = sys.argv[6]
+ provider_name = sys.argv[7] if len(sys.argv) > 7 else "Lambda Labs"
+
+ update_ssh_config(action, hostname, ip_address, username, config_file, ssh_key, provider_name)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
--
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 ` [PATCH v3 02/10] scripts: add Lambda Labs Python API library Luis Chamberlain
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 ` Luis Chamberlain [this message]
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-6-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 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.