gitarsenal-cli 1.9.75 → 1.9.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.venv_status.json +1 -1
- package/Step +0 -0
- package/package.json +1 -1
- package/python/__pycache__/credentials_manager.cpython-312.pyc +0 -0
- package/python/test_container_fail.py +239 -0
- package/python/test_container_pass.py +290 -0
- package/python/test_modalSandboxScript.py +408 -363
- package/python/test_container.py +0 -145
package/.venv_status.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"created":"2025-08-
|
|
1
|
+
{"created":"2025-08-17T05:50:53.850Z","packages":["modal","gitingest","requests","anthropic"],"uv_version":"uv 0.8.4 (Homebrew 2025-07-30)"}
|
package/Step
ADDED
|
File without changes
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import time
|
|
3
|
+
import secrets
|
|
4
|
+
import string
|
|
5
|
+
import modal
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
def generate_random_password(length=16):
|
|
10
|
+
"""Generate a random password for SSH access"""
|
|
11
|
+
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
|
12
|
+
password = ''.join(secrets.choice(alphabet) for i in range(length))
|
|
13
|
+
return password
|
|
14
|
+
|
|
15
|
+
# Image building
|
|
16
|
+
print("Building Modal image...")
|
|
17
|
+
# base_image = modal.Image.from_registry("nvidia/cuda:12.4.0-devel-ubuntu22.04", add_python="3.11")
|
|
18
|
+
base_image = modal.Image.debian_slim()
|
|
19
|
+
|
|
20
|
+
ssh_image = (
|
|
21
|
+
base_image
|
|
22
|
+
.apt_install("openssh-server", "sudo", "curl", "wget", "vim", "htop", "git", "python3", "python3-pip")
|
|
23
|
+
.uv_pip_install("uv", "modal", "gitingest", "requests", "openai", "anthropic", "exa-py")
|
|
24
|
+
.run_commands(
|
|
25
|
+
"mkdir -p /var/run/sshd",
|
|
26
|
+
"mkdir -p /root/.ssh",
|
|
27
|
+
"chmod 700 /root/.ssh",
|
|
28
|
+
"sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config",
|
|
29
|
+
"sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config",
|
|
30
|
+
"sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config",
|
|
31
|
+
"echo 'ClientAliveInterval 60' >> /etc/ssh/sshd_config",
|
|
32
|
+
"echo 'ClientAliveCountMax 3' >> /etc/ssh/sshd_config",
|
|
33
|
+
"ssh-keygen -A",
|
|
34
|
+
"echo 'export PS1=\"\\[\\e[1;32m\\]modal:\\[\\e[1;34m\\]\\w\\[\\e[0m\\]$ \"' >> /root/.bashrc",
|
|
35
|
+
"mkdir -p /python",
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
print("✅ SSH image built successfully")
|
|
40
|
+
|
|
41
|
+
# Create app
|
|
42
|
+
app = modal.App("test_container", image=ssh_image)
|
|
43
|
+
print("✅ Created app successfully")
|
|
44
|
+
|
|
45
|
+
@app.function(gpu="A10G", timeout=3600, memory=32768)
|
|
46
|
+
def get_ssh_connection(
|
|
47
|
+
test_data=None,
|
|
48
|
+
repo_info=None,
|
|
49
|
+
setup_commands=None,
|
|
50
|
+
env_vars=None,
|
|
51
|
+
credentials=None,
|
|
52
|
+
debug_config=None
|
|
53
|
+
):
|
|
54
|
+
"""Test complex remote parameter passing that causes segfault"""
|
|
55
|
+
|
|
56
|
+
print("🧪 TESTING COMPLEX REMOTE PARAMETER PASSING")
|
|
57
|
+
print("=" * 60)
|
|
58
|
+
|
|
59
|
+
# Test complex parameter handling
|
|
60
|
+
if test_data:
|
|
61
|
+
print(f"📦 Received extra_data: {type(test_data)} with {len(test_data) if hasattr(test_data, '__len__') else 'N/A'} items")
|
|
62
|
+
if isinstance(test_data, dict):
|
|
63
|
+
for key, value in test_data.items():
|
|
64
|
+
print(f" • {key}: {type(value)} = {str(value)[:100]}...")
|
|
65
|
+
|
|
66
|
+
if repo_info:
|
|
67
|
+
print(f"📂 Received repo_info: {repo_info}")
|
|
68
|
+
|
|
69
|
+
if setup_commands:
|
|
70
|
+
print(f"⚙️ Received {len(setup_commands)} setup commands:")
|
|
71
|
+
for i, cmd in enumerate(setup_commands[:3]):
|
|
72
|
+
print(f" {i+1}. {cmd}")
|
|
73
|
+
if len(setup_commands) > 3:
|
|
74
|
+
print(f" ... and {len(setup_commands) - 3} more")
|
|
75
|
+
|
|
76
|
+
if env_vars:
|
|
77
|
+
print(f"🔧 Received {len(env_vars)} environment variables:")
|
|
78
|
+
for key, value in list(env_vars.items())[:3]:
|
|
79
|
+
masked_value = str(value)[:8] + "..." if len(str(value)) > 8 else str(value)
|
|
80
|
+
print(f" • {key} = {masked_value}")
|
|
81
|
+
|
|
82
|
+
if credentials:
|
|
83
|
+
print(f"🔐 Received {len(credentials)} credentials")
|
|
84
|
+
for key in list(credentials.keys())[:3]:
|
|
85
|
+
print(f" • {key}: [MASKED]")
|
|
86
|
+
|
|
87
|
+
if debug_config:
|
|
88
|
+
print(f"🐛 Received debug_config: {debug_config}")
|
|
89
|
+
|
|
90
|
+
print("=" * 60)
|
|
91
|
+
|
|
92
|
+
# Generate SSH password
|
|
93
|
+
password = generate_random_password()
|
|
94
|
+
|
|
95
|
+
# Set root password
|
|
96
|
+
subprocess.run(["bash", "-c", f"echo 'root:{password}' | chpasswd"], check=True)
|
|
97
|
+
|
|
98
|
+
# Start SSH server
|
|
99
|
+
ssh_process = subprocess.Popen(["/usr/sbin/sshd", "-D"])
|
|
100
|
+
time.sleep(2)
|
|
101
|
+
|
|
102
|
+
# Test CUDA
|
|
103
|
+
cuda_info = {}
|
|
104
|
+
nvidia_result = subprocess.run(["nvidia-smi"], capture_output=True, text=True, timeout=30)
|
|
105
|
+
cuda_info["nvidia_smi_return_code"] = nvidia_result.returncode
|
|
106
|
+
cuda_info["nvidia_smi_output"] = nvidia_result.stdout[:500] if nvidia_result.stdout else "No output"
|
|
107
|
+
|
|
108
|
+
# nvcc_result = subprocess.run(["nvcc", "--version"], capture_output=True, text=True, timeout=30)
|
|
109
|
+
# cuda_info["nvcc_return_code"] = nvcc_result.returncode
|
|
110
|
+
# cuda_info["nvcc_output"] = nvcc_result.stdout[:500] if nvcc_result.stdout else "No output"
|
|
111
|
+
|
|
112
|
+
# Forward SSH port and return connection info
|
|
113
|
+
with modal.forward(port=22, unencrypted=True) as tunnel:
|
|
114
|
+
hostname, port = tunnel.tcp_socket
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
"status": "success",
|
|
118
|
+
"hostname": hostname,
|
|
119
|
+
"port": port,
|
|
120
|
+
"password": password,
|
|
121
|
+
"cuda_info": cuda_info,
|
|
122
|
+
"ssh_command": f"ssh -p {port} root@{hostname}",
|
|
123
|
+
"parameters_received": {
|
|
124
|
+
"test_data": bool(test_data),
|
|
125
|
+
"repo_info": bool(repo_info),
|
|
126
|
+
"setup_commands": len(setup_commands) if setup_commands else 0,
|
|
127
|
+
"env_vars": len(env_vars) if env_vars else 0,
|
|
128
|
+
"credentials": len(credentials) if credentials else 0,
|
|
129
|
+
"debug_config": bool(debug_config),
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
print("Starting CUDA container setup...")
|
|
135
|
+
|
|
136
|
+
# Check Modal authentication
|
|
137
|
+
modal_toml = os.path.expanduser("~/.modal.toml")
|
|
138
|
+
modal_dir = os.path.expanduser("~/.modal/")
|
|
139
|
+
|
|
140
|
+
if os.path.exists(modal_toml):
|
|
141
|
+
print("✓ Modal configuration found")
|
|
142
|
+
elif os.path.exists(modal_dir):
|
|
143
|
+
print("✓ Modal configuration found")
|
|
144
|
+
else:
|
|
145
|
+
print("⚠️ Warning: No Modal configuration found")
|
|
146
|
+
|
|
147
|
+
print("Initializing Modal app...")
|
|
148
|
+
print("Building container image (this may take a while on first run)...")
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
with app.run():
|
|
152
|
+
print("Getting SSH connection info...")
|
|
153
|
+
|
|
154
|
+
# THE COMPLEX DATA THAT CAUSES SEGFAULT
|
|
155
|
+
# Prepare test data to send to remote function
|
|
156
|
+
test_data = {
|
|
157
|
+
"message": "Hello from local machine!",
|
|
158
|
+
"number": 42,
|
|
159
|
+
"list": [1, 2, 3, "test"],
|
|
160
|
+
"nested": {
|
|
161
|
+
"key1": "value1",
|
|
162
|
+
"key2": 123
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
setup_commands = [
|
|
167
|
+
"apt-get update",
|
|
168
|
+
"pip install numpy",
|
|
169
|
+
"echo 'Setup complete'"
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
env_vars = {
|
|
173
|
+
"CUSTOM_VAR": "test_value",
|
|
174
|
+
"DEBUG_MODE": "true",
|
|
175
|
+
"API_URL": "https://api.example.com"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
repo_info = {
|
|
179
|
+
"url": "https://github.com/test/repo.git",
|
|
180
|
+
"branch": "main"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
credentials = {
|
|
184
|
+
"openai_api_key": "sk-test123456789abcdef",
|
|
185
|
+
"anthropic_api_key": "sk-ant-api-key-987654321",
|
|
186
|
+
"github_token": "ghp_github_token_123456",
|
|
187
|
+
"modal_token": "ak-modal-token-abcdef"
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
debug_config = {
|
|
191
|
+
"log_level": "INFO",
|
|
192
|
+
"enable_trace": True,
|
|
193
|
+
"output_file": "/tmp/debug.log",
|
|
194
|
+
"max_retries": 3
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
model_settings = {
|
|
198
|
+
"model_name": "gpt-4",
|
|
199
|
+
"temperature": 0.7,
|
|
200
|
+
"max_tokens": 2048,
|
|
201
|
+
"timeout": 30,
|
|
202
|
+
"provider": "openai"
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
print(f"📦 Sending complex data to remote function:")
|
|
206
|
+
print(f" • test_data: {len(test_data)} items (includes 1KB string)")
|
|
207
|
+
print(f" • repo_info: {len(repo_info)} items")
|
|
208
|
+
print(f" • setup_commands: {len(setup_commands)} commands")
|
|
209
|
+
print(f" • environment_vars: {len(env_vars)} variables")
|
|
210
|
+
print(f" • credentials: {len(credentials)} credentials")
|
|
211
|
+
print(f" • debug_config: {len(debug_config)} debug settings")
|
|
212
|
+
print("\n🚨 This should trigger the segfault...")
|
|
213
|
+
print()
|
|
214
|
+
|
|
215
|
+
# This call should cause the segfault
|
|
216
|
+
result = get_ssh_connection.remote(
|
|
217
|
+
test_data=test_data,
|
|
218
|
+
repo_info=repo_info,
|
|
219
|
+
setup_commands=setup_commands,
|
|
220
|
+
env_vars=env_vars,
|
|
221
|
+
credentials=credentials,
|
|
222
|
+
debug_config=debug_config
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# If we get here, it didn't segfault
|
|
226
|
+
print("\n🎉 NO SEGFAULT! Function completed successfully")
|
|
227
|
+
print(f"SSH Command: {result['ssh_command']}")
|
|
228
|
+
print(f"Password: {result['password']}")
|
|
229
|
+
|
|
230
|
+
# Keep container running
|
|
231
|
+
while True:
|
|
232
|
+
time.sleep(60)
|
|
233
|
+
print("Container still running... (Press Ctrl+C to stop)")
|
|
234
|
+
|
|
235
|
+
except Exception as e:
|
|
236
|
+
print(f"\n💥 Error occurred: {e}")
|
|
237
|
+
print("This might be the segfault or another error")
|
|
238
|
+
|
|
239
|
+
print("Container stopped")
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import time
|
|
3
|
+
import secrets
|
|
4
|
+
import string
|
|
5
|
+
import modal
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
def generate_random_password(length=16):
|
|
9
|
+
"""Generate a random password for SSH access"""
|
|
10
|
+
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
|
11
|
+
password = ''.join(secrets.choice(alphabet) for i in range(length))
|
|
12
|
+
return password
|
|
13
|
+
|
|
14
|
+
base_image = modal.Image.from_registry("nvidia/cuda:12.4.0-devel-ubuntu22.04", add_python="3.11")
|
|
15
|
+
|
|
16
|
+
ssh_image = (
|
|
17
|
+
base_image
|
|
18
|
+
.apt_install("openssh-server", "sudo", "curl", "wget", "vim", "htop", "git", "python3", "python3-pip")
|
|
19
|
+
.uv_pip_install("uv", "modal", "gitingest", "requests", "openai", "anthropic", "exa-py")
|
|
20
|
+
.run_commands(
|
|
21
|
+
"mkdir -p /var/run/sshd",
|
|
22
|
+
"mkdir -p /root/.ssh",
|
|
23
|
+
"chmod 700 /root/.ssh",
|
|
24
|
+
"sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config",
|
|
25
|
+
"sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config",
|
|
26
|
+
"sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config",
|
|
27
|
+
"echo 'ClientAliveInterval 60' >> /etc/ssh/sshd_config",
|
|
28
|
+
"echo 'ClientAliveCountMax 3' >> /etc/ssh/sshd_config",
|
|
29
|
+
"ssh-keygen -A",
|
|
30
|
+
"echo 'export PS1=\"\\[\\e[1;32m\\]modal:\\[\\e[1;34m\\]\\w\\[\\e[0m\\]$ \"' >> /root/.bashrc",
|
|
31
|
+
"mkdir -p /python",
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
print("✅ SSH image built successfully")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Create app with image passed directly (THIS IS THE KEY CHANGE)
|
|
38
|
+
print("🔍 Testing app creation...")
|
|
39
|
+
app = modal.App("test_container", image=ssh_image) # Pass image here
|
|
40
|
+
print("✅ Created app successfully")
|
|
41
|
+
|
|
42
|
+
# Define the SSH container function (remove image from decorator)
|
|
43
|
+
@app.function(
|
|
44
|
+
timeout= 3600, # Convert to seconds
|
|
45
|
+
gpu="A10G", # Use the user-selected GPU type and count
|
|
46
|
+
serialized=True,
|
|
47
|
+
# volumes=volumes_config if volumes_config else None,
|
|
48
|
+
memory=32768,
|
|
49
|
+
)
|
|
50
|
+
def start_ssh():
|
|
51
|
+
# Generate SSH password
|
|
52
|
+
password = generate_random_password()
|
|
53
|
+
|
|
54
|
+
# Set root password
|
|
55
|
+
subprocess.run(["bash", "-c", f"echo 'root:{password}' | chpasswd"], check=True)
|
|
56
|
+
|
|
57
|
+
# Start SSH server
|
|
58
|
+
ssh_process = subprocess.Popen(["/usr/sbin/sshd", "-D"])
|
|
59
|
+
time.sleep(2)
|
|
60
|
+
|
|
61
|
+
# Test CUDA
|
|
62
|
+
cuda_info = {}
|
|
63
|
+
nvidia_result = subprocess.run(["nvidia-smi"], capture_output=True, text=True, timeout=30)
|
|
64
|
+
cuda_info["nvidia_smi_output"] = nvidia_result.stdout if nvidia_result.stdout else "No output"
|
|
65
|
+
|
|
66
|
+
nvcc_result = subprocess.run(["nvcc", "--version"], capture_output=True, text=True, timeout=30)
|
|
67
|
+
cuda_info["nvcc_output"] = nvcc_result.stdout if nvcc_result.stdout else "No output"
|
|
68
|
+
|
|
69
|
+
# Forward SSH port
|
|
70
|
+
with modal.forward(port=22, unencrypted=True) as tunnel:
|
|
71
|
+
hostname, port = tunnel.tcp_socket
|
|
72
|
+
|
|
73
|
+
# Return connection info to local terminal
|
|
74
|
+
connection_info = {
|
|
75
|
+
"hostname": hostname,
|
|
76
|
+
"port": port,
|
|
77
|
+
"password": password,
|
|
78
|
+
"cuda_info": cuda_info,
|
|
79
|
+
"status": "success"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Keep alive with periodic status updates
|
|
83
|
+
counter = 0
|
|
84
|
+
while True:
|
|
85
|
+
counter += 1
|
|
86
|
+
time.sleep(60)
|
|
87
|
+
|
|
88
|
+
@app.function(gpu="A10G", timeout=3600)
|
|
89
|
+
def get_ssh_connection(test_data=None, setup_commands=None, env_vars=None, repo_info=None,
|
|
90
|
+
credentials=None, debug_config=None, model_settings=None):
|
|
91
|
+
"""Get SSH connection info and test remote parameter passing"""
|
|
92
|
+
|
|
93
|
+
print("🧪 REMOTE FUNCTION - Testing parameter passing...")
|
|
94
|
+
print("=" * 50)
|
|
95
|
+
|
|
96
|
+
if test_data:
|
|
97
|
+
print(f"📦 Received test_data: {type(test_data)}")
|
|
98
|
+
if isinstance(test_data, dict):
|
|
99
|
+
for key, value in test_data.items():
|
|
100
|
+
print(f" • {key}: {value}")
|
|
101
|
+
elif isinstance(test_data, list):
|
|
102
|
+
print(f" • List with {len(test_data)} items: {test_data}")
|
|
103
|
+
else:
|
|
104
|
+
print(f" • Value: {test_data}")
|
|
105
|
+
|
|
106
|
+
if setup_commands:
|
|
107
|
+
print(f"⚙️ Received {len(setup_commands)} setup commands:")
|
|
108
|
+
for i, cmd in enumerate(setup_commands):
|
|
109
|
+
print(f" {i+1}. {cmd}")
|
|
110
|
+
|
|
111
|
+
if env_vars:
|
|
112
|
+
print(f"🔧 Received {len(env_vars)} environment variables:")
|
|
113
|
+
for key, value in env_vars.items():
|
|
114
|
+
print(f" • {key} = {value}")
|
|
115
|
+
|
|
116
|
+
if repo_info:
|
|
117
|
+
print(f"📂 Received repo_info: {repo_info}")
|
|
118
|
+
|
|
119
|
+
if credentials:
|
|
120
|
+
print(f"🔐 Received {len(credentials)} credentials:")
|
|
121
|
+
for key, value in credentials.items():
|
|
122
|
+
# Mask sensitive data
|
|
123
|
+
masked_value = value[:8] + "..." if len(str(value)) > 8 else "***"
|
|
124
|
+
print(f" • {key}: {masked_value}")
|
|
125
|
+
|
|
126
|
+
if debug_config:
|
|
127
|
+
print(f"🐛 Received debug_config:")
|
|
128
|
+
for key, value in debug_config.items():
|
|
129
|
+
print(f" • {key}: {value}")
|
|
130
|
+
|
|
131
|
+
if model_settings:
|
|
132
|
+
print(f"🤖 Received model_settings:")
|
|
133
|
+
for key, value in model_settings.items():
|
|
134
|
+
print(f" • {key}: {value}")
|
|
135
|
+
|
|
136
|
+
print("=" * 50)
|
|
137
|
+
|
|
138
|
+
# Generate SSH password
|
|
139
|
+
password = generate_random_password()
|
|
140
|
+
|
|
141
|
+
# Set root password
|
|
142
|
+
subprocess.run(["bash", "-c", f"echo 'root:{password}' | chpasswd"], check=True)
|
|
143
|
+
|
|
144
|
+
# Start SSH server
|
|
145
|
+
ssh_process = subprocess.Popen(["/usr/sbin/sshd", "-D"])
|
|
146
|
+
time.sleep(2)
|
|
147
|
+
|
|
148
|
+
# Test CUDA
|
|
149
|
+
cuda_info = {}
|
|
150
|
+
nvidia_result = subprocess.run(["nvidia-smi"], capture_output=True, text=True, timeout=30)
|
|
151
|
+
cuda_info["nvidia_smi_return_code"] = nvidia_result.returncode
|
|
152
|
+
cuda_info["nvidia_smi_output"] = nvidia_result.stdout[:500] if nvidia_result.stdout else "No output"
|
|
153
|
+
|
|
154
|
+
nvcc_result = subprocess.run(["nvcc", "--version"], capture_output=True, text=True, timeout=30)
|
|
155
|
+
cuda_info["nvcc_return_code"] = nvcc_result.returncode
|
|
156
|
+
cuda_info["nvcc_output"] = nvcc_result.stdout[:500] if nvcc_result.stdout else "No output"
|
|
157
|
+
|
|
158
|
+
# Forward SSH port and return connection info
|
|
159
|
+
with modal.forward(port=22, unencrypted=True) as tunnel:
|
|
160
|
+
hostname, port = tunnel.tcp_socket
|
|
161
|
+
|
|
162
|
+
# Return connection info immediately
|
|
163
|
+
return {
|
|
164
|
+
"status": "success",
|
|
165
|
+
"hostname": hostname,
|
|
166
|
+
"port": port,
|
|
167
|
+
"password": password,
|
|
168
|
+
"cuda_info": cuda_info,
|
|
169
|
+
"ssh_command": f"ssh -p {port} root@{hostname}"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
print("Starting CUDA container setup...")
|
|
174
|
+
|
|
175
|
+
# Check Modal authentication files
|
|
176
|
+
import os
|
|
177
|
+
modal_toml = os.path.expanduser("~/.modal.toml")
|
|
178
|
+
modal_dir = os.path.expanduser("~/.modal/")
|
|
179
|
+
|
|
180
|
+
if os.path.exists(modal_toml):
|
|
181
|
+
print("✓ Modal configuration found")
|
|
182
|
+
elif os.path.exists(modal_dir):
|
|
183
|
+
print("✓ Modal configuration found")
|
|
184
|
+
else:
|
|
185
|
+
print("⚠️ Warning: No Modal configuration found")
|
|
186
|
+
|
|
187
|
+
print("Initializing Modal app...")
|
|
188
|
+
print("Building container image (this may take a while on first run)...")
|
|
189
|
+
|
|
190
|
+
with app.run():
|
|
191
|
+
print("Getting SSH connection info...")
|
|
192
|
+
|
|
193
|
+
# Prepare test data to send to remote function
|
|
194
|
+
test_data = {
|
|
195
|
+
"message": "Hello from local machine!",
|
|
196
|
+
"number": 42,
|
|
197
|
+
"list": [1, 2, 3, "test"],
|
|
198
|
+
"nested": {
|
|
199
|
+
"key1": "value1",
|
|
200
|
+
"key2": 123
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
setup_commands = [
|
|
205
|
+
"apt-get update",
|
|
206
|
+
"pip install numpy",
|
|
207
|
+
"echo 'Setup complete'"
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
env_vars = {
|
|
211
|
+
"CUSTOM_VAR": "test_value",
|
|
212
|
+
"DEBUG_MODE": "true",
|
|
213
|
+
"API_URL": "https://api.example.com"
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
repo_info = {
|
|
217
|
+
"url": "https://github.com/test/repo.git",
|
|
218
|
+
"branch": "main"
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
credentials = {
|
|
222
|
+
"openai_api_key": "sk-test123456789abcdef",
|
|
223
|
+
"anthropic_api_key": "sk-ant-api-key-987654321",
|
|
224
|
+
"github_token": "ghp_github_token_123456",
|
|
225
|
+
"modal_token": "ak-modal-token-abcdef"
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
debug_config = {
|
|
229
|
+
"log_level": "INFO",
|
|
230
|
+
"enable_trace": True,
|
|
231
|
+
"output_file": "/tmp/debug.log",
|
|
232
|
+
"max_retries": 3
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
model_settings = {
|
|
236
|
+
"model_name": "gpt-4",
|
|
237
|
+
"temperature": 0.7,
|
|
238
|
+
"max_tokens": 2048,
|
|
239
|
+
"timeout": 30,
|
|
240
|
+
"provider": "openai"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
print("📦 Sending test parameters to remote function:")
|
|
244
|
+
print(f" • test_data: {len(test_data)} items")
|
|
245
|
+
print(f" • setup_commands: {len(setup_commands)} commands")
|
|
246
|
+
print(f" • env_vars: {len(env_vars)} variables")
|
|
247
|
+
print(f" • repo_info: {repo_info}")
|
|
248
|
+
print(f" • credentials: {len(credentials)} items")
|
|
249
|
+
print(f" • debug_config: {len(debug_config)} items")
|
|
250
|
+
print(f" • model_settings: {len(model_settings)} items")
|
|
251
|
+
print()
|
|
252
|
+
|
|
253
|
+
# Get connection info with test parameters
|
|
254
|
+
result = get_ssh_connection.remote(
|
|
255
|
+
test_data=test_data,
|
|
256
|
+
setup_commands=setup_commands,
|
|
257
|
+
env_vars=env_vars,
|
|
258
|
+
repo_info=repo_info,
|
|
259
|
+
credentials=credentials,
|
|
260
|
+
debug_config=debug_config,
|
|
261
|
+
model_settings=model_settings
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
if result and "error" not in result:
|
|
265
|
+
print("\n" + "="*60)
|
|
266
|
+
print("🚀 CUDA CONTAINER READY!")
|
|
267
|
+
print("="*60)
|
|
268
|
+
print(f"SSH Command: {result['ssh_command']}")
|
|
269
|
+
print(f"Password: {result['password']}")
|
|
270
|
+
print("="*60)
|
|
271
|
+
|
|
272
|
+
print("\n📊 CUDA Information:")
|
|
273
|
+
if "nvidia_smi_output" in result["cuda_info"]:
|
|
274
|
+
print("nvidia-smi output:")
|
|
275
|
+
print(result["cuda_info"]["nvidia_smi_output"])
|
|
276
|
+
if "nvcc_output" in result["cuda_info"]:
|
|
277
|
+
print("\nnvcc output:")
|
|
278
|
+
print(result["cuda_info"]["nvcc_output"])
|
|
279
|
+
|
|
280
|
+
print("\n⚠️ Note: Container will stay running until you stop this script")
|
|
281
|
+
print("Press Ctrl+C to stop the container")
|
|
282
|
+
|
|
283
|
+
# Keep the local script running to maintain the container
|
|
284
|
+
while True:
|
|
285
|
+
time.sleep(60)
|
|
286
|
+
print("Container still running... (Press Ctrl+C to stop)")
|
|
287
|
+
else:
|
|
288
|
+
print(f"\n❌ Error: {result.get('error', 'Unknown error')}")
|
|
289
|
+
|
|
290
|
+
print("Container stopped")
|