gitarsenal-cli 1.1.8 → 1.1.10
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/package.json +1 -1
- package/python/__pycache__/gitarsenal_proxy_client.cpython-313.pyc +0 -0
- package/python/__pycache__/test_modalSandboxScript.cpython-313.pyc +0 -0
- package/python/gitarsenal.py +121 -420
- package/python/modal_proxy_service.py +22 -0
- package/python/test_modalSandboxScript.py +56 -11
package/package.json
CHANGED
Binary file
|
Binary file
|
package/python/gitarsenal.py
CHANGED
@@ -109,483 +109,184 @@ def check_proxy_config():
|
|
109
109
|
return False
|
110
110
|
|
111
111
|
def main():
|
112
|
-
|
112
|
+
"""Main entry point for the GitArsenal CLI"""
|
113
|
+
parser = argparse.ArgumentParser(description="GitArsenal CLI - Tools for AI development")
|
113
114
|
subparsers = parser.add_subparsers(dest="command", help="Command to run")
|
114
115
|
|
115
|
-
# Credentials command
|
116
|
-
cred_parser = subparsers.add_parser("credentials", help="Manage credentials")
|
117
|
-
cred_subparsers = cred_parser.add_subparsers(dest="cred_command", help="Credentials command")
|
118
|
-
|
119
|
-
# Credentials setup command
|
120
|
-
cred_setup_parser = cred_subparsers.add_parser("setup", help="Set up all credentials")
|
121
|
-
|
122
|
-
# Credentials set command
|
123
|
-
cred_set_parser = cred_subparsers.add_parser("set", help="Set a specific credential")
|
124
|
-
cred_set_parser.add_argument("key", choices=["openai_api_key", "modal_token", "huggingface_token", "wandb_api_key"],
|
125
|
-
help="The credential to set")
|
126
|
-
|
127
|
-
# Credentials get command
|
128
|
-
cred_get_parser = cred_subparsers.add_parser("get", help="Get a specific credential")
|
129
|
-
cred_get_parser.add_argument("key", choices=["openai_api_key", "modal_token", "huggingface_token", "wandb_api_key"],
|
130
|
-
help="The credential to get")
|
131
|
-
|
132
|
-
# Credentials clear command
|
133
|
-
cred_clear_parser = cred_subparsers.add_parser("clear", help="Clear credentials")
|
134
|
-
cred_clear_parser.add_argument("key", nargs="?", choices=["openai_api_key", "modal_token", "huggingface_token", "wandb_api_key", "all"],
|
135
|
-
default="all", help="The credential to clear (default: all)")
|
136
|
-
|
137
|
-
# Credentials list command
|
138
|
-
cred_list_parser = cred_subparsers.add_parser("list", help="List all saved credentials")
|
139
|
-
|
140
|
-
# Sandbox command
|
141
|
-
sandbox_parser = subparsers.add_parser("sandbox", help="Create a Modal sandbox")
|
142
|
-
sandbox_parser.add_argument("--gpu", type=str, default="A10G", choices=["A10G", "A100", "H100", "T4", "V100"],
|
143
|
-
help="GPU type (default: A10G)")
|
144
|
-
sandbox_parser.add_argument("--repo-url", type=str, help="Repository URL to clone")
|
145
|
-
sandbox_parser.add_argument("--repo-name", type=str, help="Repository name override")
|
146
|
-
sandbox_parser.add_argument("--setup-commands", type=str, nargs="+", help="Setup commands to run")
|
147
|
-
sandbox_parser.add_argument("--volume-name", type=str, help="Name of the Modal volume for persistent storage")
|
148
|
-
sandbox_parser.add_argument("--use-api", action="store_true", help="Use API for setup commands")
|
149
|
-
sandbox_parser.add_argument("--use-proxy", action="store_true", help="Use Modal proxy service instead of direct Modal access")
|
150
|
-
|
151
116
|
# SSH command
|
152
117
|
ssh_parser = subparsers.add_parser("ssh", help="Create a Modal SSH container")
|
153
|
-
ssh_parser.add_argument("--gpu", type=str, default="A10G",
|
154
|
-
help="GPU type (default: A10G)")
|
118
|
+
ssh_parser.add_argument("--gpu", type=str, default="A10G", help="GPU type (default: A10G)")
|
155
119
|
ssh_parser.add_argument("--repo-url", type=str, help="Repository URL to clone")
|
156
120
|
ssh_parser.add_argument("--repo-name", type=str, help="Repository name override")
|
157
|
-
ssh_parser.add_argument("--
|
158
|
-
ssh_parser.add_argument("--volume-name", type=str, help="Name of the Modal volume for persistent storage")
|
121
|
+
ssh_parser.add_argument("--volume-name", type=str, help="Volume name for persistent storage")
|
159
122
|
ssh_parser.add_argument("--timeout", type=int, default=60, help="Container timeout in minutes (default: 60)")
|
160
|
-
ssh_parser.add_argument("--use-
|
161
|
-
ssh_parser.add_argument("--
|
123
|
+
ssh_parser.add_argument("--use-proxy", action="store_true", help="Use Modal proxy service instead of direct Modal API")
|
124
|
+
ssh_parser.add_argument("--wait", action="store_true", help="Wait for container to be ready")
|
125
|
+
|
126
|
+
# Sandbox command
|
127
|
+
sandbox_parser = subparsers.add_parser("sandbox", help="Create a Modal sandbox")
|
128
|
+
sandbox_parser.add_argument("--gpu", type=str, default="A10G", help="GPU type (default: A10G)")
|
129
|
+
sandbox_parser.add_argument("--repo-url", type=str, help="Repository URL to clone")
|
130
|
+
sandbox_parser.add_argument("--repo-name", type=str, help="Repository name override")
|
131
|
+
sandbox_parser.add_argument("--volume-name", type=str, help="Volume name for persistent storage")
|
132
|
+
sandbox_parser.add_argument("--use-proxy", action="store_true", help="Use Modal proxy service instead of direct Modal API")
|
133
|
+
sandbox_parser.add_argument("--wait", action="store_true", help="Wait for container to be ready")
|
162
134
|
|
163
|
-
# Proxy
|
164
|
-
proxy_parser = subparsers.add_parser("proxy", help="
|
165
|
-
proxy_subparsers = proxy_parser.add_subparsers(dest="proxy_command", help="Proxy command")
|
135
|
+
# Proxy commands
|
136
|
+
proxy_parser = subparsers.add_parser("proxy", help="Modal proxy service commands")
|
137
|
+
proxy_subparsers = proxy_parser.add_subparsers(dest="proxy_command", help="Proxy command to run")
|
166
138
|
|
167
139
|
# Proxy configure command
|
168
|
-
proxy_configure_parser = proxy_subparsers.add_parser("configure", help="Configure
|
140
|
+
proxy_configure_parser = proxy_subparsers.add_parser("configure", help="Configure proxy settings")
|
169
141
|
|
170
142
|
# Proxy status command
|
171
|
-
proxy_status_parser = proxy_subparsers.add_parser("status", help="Check
|
172
|
-
|
173
|
-
# Proxy sandbox command
|
174
|
-
proxy_sandbox_parser = proxy_subparsers.add_parser("sandbox", help="Create a sandbox through Modal proxy")
|
175
|
-
proxy_sandbox_parser.add_argument("--gpu", type=str, default="A10G", choices=["A10G", "A100", "H100", "T4", "V100"],
|
176
|
-
help="GPU type (default: A10G)")
|
177
|
-
proxy_sandbox_parser.add_argument("--repo-url", type=str, help="Repository URL to clone")
|
178
|
-
proxy_sandbox_parser.add_argument("--repo-name", type=str, help="Repository name override")
|
179
|
-
proxy_sandbox_parser.add_argument("--setup-commands", type=str, nargs="+", help="Setup commands to run")
|
180
|
-
proxy_sandbox_parser.add_argument("--volume-name", type=str, help="Name of the Modal volume for persistent storage")
|
181
|
-
proxy_sandbox_parser.add_argument("--wait", action="store_true", help="Wait for sandbox to be ready")
|
143
|
+
proxy_status_parser = proxy_subparsers.add_parser("status", help="Check proxy status")
|
182
144
|
|
183
|
-
# Proxy
|
184
|
-
proxy_ssh_parser = proxy_subparsers.add_parser("ssh", help="Create
|
185
|
-
proxy_ssh_parser.add_argument("--gpu", type=str, default="A10G",
|
186
|
-
help="GPU type (default: A10G)")
|
145
|
+
# Proxy SSH command
|
146
|
+
proxy_ssh_parser = proxy_subparsers.add_parser("ssh", help="Create SSH container through proxy")
|
147
|
+
proxy_ssh_parser.add_argument("--gpu", type=str, default="A10G", help="GPU type (default: A10G)")
|
187
148
|
proxy_ssh_parser.add_argument("--repo-url", type=str, help="Repository URL to clone")
|
188
149
|
proxy_ssh_parser.add_argument("--repo-name", type=str, help="Repository name override")
|
189
|
-
proxy_ssh_parser.add_argument("--
|
190
|
-
proxy_ssh_parser.add_argument("--volume-name", type=str, help="Name of the Modal volume for persistent storage")
|
150
|
+
proxy_ssh_parser.add_argument("--volume-name", type=str, help="Volume name for persistent storage")
|
191
151
|
proxy_ssh_parser.add_argument("--timeout", type=int, default=60, help="Container timeout in minutes (default: 60)")
|
192
152
|
proxy_ssh_parser.add_argument("--wait", action="store_true", help="Wait for container to be ready")
|
193
153
|
|
154
|
+
# Parse arguments
|
194
155
|
args = parser.parse_args()
|
195
156
|
|
196
|
-
if
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
if not check_proxy_config():
|
206
|
-
print("\n⚠️ Modal proxy service is not configured.")
|
207
|
-
print("Please run './gitarsenal.py proxy configure' first.")
|
208
|
-
return 1
|
209
|
-
else:
|
210
|
-
# Check if Modal is authenticated
|
211
|
-
if not check_modal_auth():
|
212
|
-
print("\n⚠️ Please authenticate with Modal before proceeding.")
|
213
|
-
return 1
|
214
|
-
|
215
|
-
# Try to load credentials and set Modal token if available
|
216
|
-
try:
|
217
|
-
from credentials_manager import CredentialsManager
|
218
|
-
credentials_manager = CredentialsManager()
|
219
|
-
credentials = credentials_manager.load_credentials()
|
220
|
-
|
221
|
-
if "modal_token" in credentials:
|
222
|
-
# Set the Modal token in the environment
|
223
|
-
os.environ["MODAL_TOKEN_ID"] = credentials["modal_token"]
|
224
|
-
print("✅ Using Modal token from credentials")
|
225
|
-
|
226
|
-
# Try to authenticate with the token
|
227
|
-
try:
|
228
|
-
token_result = subprocess.run(
|
229
|
-
["modal", "token", "set", credentials["modal_token"]],
|
230
|
-
capture_output=True, text=True
|
231
|
-
)
|
232
|
-
if token_result.returncode == 0:
|
233
|
-
print("✅ Successfully authenticated with Modal")
|
234
|
-
except Exception as e:
|
235
|
-
print(f"⚠️ Error setting Modal token: {e}")
|
236
|
-
except ImportError:
|
237
|
-
print("⚠️ Could not load credentials manager")
|
238
|
-
except Exception as e:
|
239
|
-
print(f"⚠️ Error loading credentials: {e}")
|
240
|
-
|
241
|
-
# Handle credentials commands
|
242
|
-
if args.command == "credentials":
|
243
|
-
try:
|
244
|
-
from credentials_manager import CredentialsManager
|
245
|
-
credentials_manager = CredentialsManager()
|
246
|
-
|
247
|
-
if args.cred_command == "setup":
|
248
|
-
# Set up all credentials
|
249
|
-
print("🔧 Setting up all credentials")
|
250
|
-
|
251
|
-
# Modal token
|
252
|
-
modal_token = credentials_manager.get_modal_token()
|
253
|
-
if modal_token:
|
254
|
-
print("✅ Modal token set")
|
255
|
-
else:
|
256
|
-
print("⚠️ Modal token not set")
|
257
|
-
|
258
|
-
# OpenAI API key
|
259
|
-
openai_api_key = credentials_manager.get_openai_api_key()
|
260
|
-
if openai_api_key:
|
261
|
-
print("✅ OpenAI API key set")
|
262
|
-
else:
|
263
|
-
print("⚠️ OpenAI API key not set")
|
264
|
-
|
265
|
-
# Hugging Face token
|
266
|
-
huggingface_token = credentials_manager.get_huggingface_token()
|
267
|
-
if huggingface_token:
|
268
|
-
print("✅ Hugging Face token set")
|
269
|
-
else:
|
270
|
-
print("⚠️ Hugging Face token not set")
|
271
|
-
|
272
|
-
# Weights & Biases API key
|
273
|
-
wandb_api_key = credentials_manager.get_wandb_api_key()
|
274
|
-
if wandb_api_key:
|
275
|
-
print("✅ Weights & Biases API key set")
|
276
|
-
else:
|
277
|
-
print("⚠️ Weights & Biases API key not set")
|
278
|
-
|
279
|
-
elif args.cred_command == "set":
|
280
|
-
# Set a specific credential
|
281
|
-
if args.key == "modal_token":
|
282
|
-
modal_token = credentials_manager.get_modal_token()
|
283
|
-
if modal_token:
|
284
|
-
print("✅ Modal token set")
|
285
|
-
else:
|
286
|
-
print("⚠️ Modal token not set")
|
287
|
-
elif args.key == "openai_api_key":
|
288
|
-
openai_api_key = credentials_manager.get_openai_api_key()
|
289
|
-
if openai_api_key:
|
290
|
-
print("✅ OpenAI API key set")
|
291
|
-
else:
|
292
|
-
print("⚠️ OpenAI API key not set")
|
293
|
-
elif args.key == "huggingface_token":
|
294
|
-
huggingface_token = credentials_manager.get_huggingface_token()
|
295
|
-
if huggingface_token:
|
296
|
-
print("✅ Hugging Face token set")
|
297
|
-
else:
|
298
|
-
print("⚠️ Hugging Face token not set")
|
299
|
-
elif args.key == "wandb_api_key":
|
300
|
-
wandb_api_key = credentials_manager.get_wandb_api_key()
|
301
|
-
if wandb_api_key:
|
302
|
-
print("✅ Weights & Biases API key set")
|
303
|
-
else:
|
304
|
-
print("⚠️ Weights & Biases API key not set")
|
305
|
-
|
306
|
-
elif args.cred_command == "get":
|
307
|
-
# Get a specific credential
|
308
|
-
credentials = credentials_manager.load_credentials()
|
309
|
-
if args.key in credentials:
|
310
|
-
# Mask the credential for security
|
311
|
-
value = credentials[args.key]
|
312
|
-
masked_value = value[:4] + "*" * (len(value) - 8) + value[-4:] if len(value) > 8 else "****"
|
313
|
-
print(f"{args.key}: {masked_value}")
|
314
|
-
else:
|
315
|
-
print(f"⚠️ {args.key} not found")
|
316
|
-
|
317
|
-
elif args.cred_command == "clear":
|
318
|
-
# Clear credentials
|
319
|
-
if args.key == "all":
|
320
|
-
credentials_manager.clear_all_credentials()
|
321
|
-
print("✅ All credentials cleared")
|
322
|
-
else:
|
323
|
-
if credentials_manager.clear_credential(args.key):
|
324
|
-
print(f"✅ {args.key} cleared")
|
325
|
-
else:
|
326
|
-
print(f"⚠️ {args.key} not found")
|
327
|
-
|
328
|
-
elif args.cred_command == "list":
|
329
|
-
# List all credentials
|
330
|
-
credentials = credentials_manager.load_credentials()
|
331
|
-
if credentials:
|
332
|
-
print("📋 Saved credentials:")
|
333
|
-
for key in credentials:
|
334
|
-
print(f" - {key}")
|
335
|
-
else:
|
336
|
-
print("⚠️ No credentials found")
|
337
|
-
|
338
|
-
else:
|
339
|
-
print("⚠️ Unknown credentials command")
|
340
|
-
return 1
|
341
|
-
|
342
|
-
except ImportError:
|
343
|
-
print("❌ Could not import credentials_manager module")
|
344
|
-
return 1
|
345
|
-
except Exception as e:
|
346
|
-
print(f"❌ Error: {e}")
|
347
|
-
return 1
|
348
|
-
|
349
|
-
# Handle sandbox command
|
350
|
-
elif args.command == "sandbox":
|
351
|
-
try:
|
352
|
-
# Check if using proxy service
|
353
|
-
if args.use_proxy:
|
354
|
-
# Import proxy client
|
355
|
-
try:
|
356
|
-
from gitarsenal_proxy_client import GitArsenalProxyClient
|
357
|
-
client = GitArsenalProxyClient()
|
358
|
-
|
359
|
-
# Create sandbox through proxy
|
360
|
-
result = client.create_sandbox(
|
361
|
-
gpu_type=args.gpu,
|
362
|
-
repo_url=args.repo_url,
|
363
|
-
repo_name=args.repo_name,
|
364
|
-
setup_commands=args.setup_commands,
|
365
|
-
volume_name=args.volume_name,
|
366
|
-
wait=True # Always wait for sandbox to be ready
|
367
|
-
)
|
368
|
-
|
369
|
-
if not result:
|
370
|
-
print("❌ Failed to create sandbox through proxy service")
|
371
|
-
return 1
|
372
|
-
|
373
|
-
print("✅ Sandbox created successfully through proxy service")
|
374
|
-
|
375
|
-
except ImportError:
|
376
|
-
print("❌ Could not import gitarsenal_proxy_client module")
|
377
|
-
print("Please make sure gitarsenal_proxy_client.py is in the same directory")
|
378
|
-
return 1
|
379
|
-
else:
|
380
|
-
# Import sandbox creation function
|
381
|
-
from test_modalSandboxScript import create_modal_sandbox
|
382
|
-
|
383
|
-
# Create sandbox directly
|
384
|
-
result = create_modal_sandbox(
|
385
|
-
args.gpu,
|
157
|
+
if args.command == "ssh":
|
158
|
+
if args.use_proxy:
|
159
|
+
# Use proxy service for SSH container
|
160
|
+
print("🚀 Creating SSH container through proxy...")
|
161
|
+
if check_proxy_config():
|
162
|
+
from gitarsenal_proxy_client import GitArsenalProxyClient
|
163
|
+
client = GitArsenalProxyClient()
|
164
|
+
result = client.create_ssh_container(
|
165
|
+
gpu_type=args.gpu,
|
386
166
|
repo_url=args.repo_url,
|
387
167
|
repo_name=args.repo_name,
|
388
|
-
|
389
|
-
|
168
|
+
volume_name=args.volume_name,
|
169
|
+
timeout=args.timeout,
|
170
|
+
wait=args.wait
|
390
171
|
)
|
391
|
-
|
392
|
-
if not result:
|
393
|
-
print("❌ Failed to create sandbox")
|
394
|
-
return 1
|
395
|
-
|
396
|
-
print("✅ Sandbox created successfully")
|
397
|
-
|
398
|
-
except ImportError as e:
|
399
|
-
print(f"❌ Could not import required module: {e}")
|
400
|
-
return 1
|
401
|
-
except Exception as e:
|
402
|
-
print(f"❌ Error: {e}")
|
403
|
-
return 1
|
404
|
-
|
405
|
-
# Handle SSH command
|
406
|
-
elif args.command == "ssh":
|
407
|
-
try:
|
408
|
-
# Check if using proxy service
|
409
|
-
if args.use_proxy:
|
410
|
-
# Import proxy client
|
411
|
-
try:
|
412
|
-
from gitarsenal_proxy_client import GitArsenalProxyClient
|
413
|
-
client = GitArsenalProxyClient()
|
414
|
-
|
415
|
-
# Ensure proxy is configured
|
416
|
-
config = client.load_config()
|
417
|
-
if not config.get("proxy_url") or not config.get("api_key"):
|
418
|
-
print("\n⚠️ Modal proxy service is not fully configured.")
|
419
|
-
print("Running configuration wizard...")
|
420
|
-
client.configure(interactive=True)
|
421
|
-
# Reload config after configuration
|
422
|
-
config = client.load_config()
|
423
|
-
if not config.get("proxy_url") or not config.get("api_key"):
|
424
|
-
print("❌ Proxy configuration failed or was cancelled.")
|
425
|
-
return 1
|
426
|
-
print("✅ Proxy configuration completed successfully.")
|
427
|
-
|
428
|
-
# Create SSH container through proxy
|
429
|
-
print(f"🚀 Creating SSH container through proxy service ({config.get('proxy_url')})")
|
430
|
-
result = client.create_ssh_container(
|
431
|
-
gpu_type=args.gpu,
|
432
|
-
repo_url=args.repo_url,
|
433
|
-
repo_name=args.repo_name,
|
434
|
-
setup_commands=args.setup_commands,
|
435
|
-
volume_name=args.volume_name,
|
436
|
-
timeout=args.timeout,
|
437
|
-
wait=True # Always wait for container to be ready
|
438
|
-
)
|
439
|
-
|
440
|
-
if not result:
|
441
|
-
print("❌ Failed to create SSH container through proxy service")
|
442
|
-
return 1
|
443
|
-
|
172
|
+
if result:
|
444
173
|
print("✅ SSH container created successfully through proxy service")
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
174
|
+
print(f"📋 Container ID: {result.get('container_id')}")
|
175
|
+
print(f"🔐 SSH Password: {result.get('ssh_password')}")
|
176
|
+
if not args.wait:
|
177
|
+
print("\n⚠️ Container creation is asynchronous. Use --wait flag to wait for it to be ready.")
|
178
|
+
print(" You can check the status later using the container ID above.")
|
179
|
+
else:
|
180
|
+
print("❌ Failed to create SSH container through proxy service")
|
450
181
|
else:
|
451
|
-
|
182
|
+
print("❌ Proxy configuration failed or was cancelled.")
|
183
|
+
else:
|
184
|
+
# Use direct Modal API for SSH container
|
185
|
+
print("🚀 Creating SSH container...")
|
186
|
+
if check_modal_auth():
|
187
|
+
# Import the SSH container creation function
|
452
188
|
from test_modalSandboxScript import create_modal_ssh_container
|
453
|
-
|
454
|
-
# Create SSH container directly
|
455
189
|
result = create_modal_ssh_container(
|
456
190
|
args.gpu,
|
457
191
|
repo_url=args.repo_url,
|
458
192
|
repo_name=args.repo_name,
|
459
|
-
setup_commands=args.setup_commands,
|
460
193
|
volume_name=args.volume_name,
|
461
194
|
timeout_minutes=args.timeout
|
462
195
|
)
|
463
|
-
|
464
|
-
|
196
|
+
if result:
|
197
|
+
print("✅ SSH container created successfully")
|
198
|
+
else:
|
465
199
|
print("❌ Failed to create SSH container")
|
466
|
-
|
467
|
-
|
468
|
-
print("✅ SSH container created successfully")
|
469
|
-
|
470
|
-
except ImportError as e:
|
471
|
-
print(f"❌ Could not import required module: {e}")
|
472
|
-
return 1
|
473
|
-
except Exception as e:
|
474
|
-
print(f"❌ Error: {e}")
|
475
|
-
return 1
|
200
|
+
else:
|
201
|
+
print("❌ Modal authentication failed or was cancelled.")
|
476
202
|
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
# Import proxy client
|
485
|
-
from gitarsenal_proxy_client import GitArsenalProxyClient
|
486
|
-
client = GitArsenalProxyClient()
|
487
|
-
|
488
|
-
if args.proxy_command == "configure":
|
489
|
-
# Configure proxy service
|
490
|
-
client.configure(interactive=True)
|
491
|
-
|
492
|
-
elif args.proxy_command == "status":
|
493
|
-
# Check proxy service status
|
494
|
-
response = client.health_check()
|
495
|
-
if response["success"]:
|
496
|
-
print(f"✅ Proxy service is running: {response['data']['message']}")
|
497
|
-
else:
|
498
|
-
print(f"❌ Proxy service health check failed: {response['error']}")
|
499
|
-
return 1
|
500
|
-
|
501
|
-
elif args.proxy_command == "sandbox":
|
502
|
-
# Create sandbox through proxy
|
203
|
+
elif args.command == "sandbox":
|
204
|
+
if args.use_proxy:
|
205
|
+
# Use proxy service for sandbox
|
206
|
+
print("🚀 Creating sandbox through proxy...")
|
207
|
+
if check_proxy_config():
|
208
|
+
from gitarsenal_proxy_client import GitArsenalProxyClient
|
209
|
+
client = GitArsenalProxyClient()
|
503
210
|
result = client.create_sandbox(
|
504
211
|
gpu_type=args.gpu,
|
505
212
|
repo_url=args.repo_url,
|
506
213
|
repo_name=args.repo_name,
|
507
|
-
setup_commands=args.setup_commands,
|
508
214
|
volume_name=args.volume_name,
|
509
215
|
wait=args.wait
|
510
216
|
)
|
511
|
-
|
512
|
-
|
217
|
+
if result:
|
218
|
+
print("✅ Sandbox created successfully through proxy service")
|
219
|
+
else:
|
513
220
|
print("❌ Failed to create sandbox through proxy service")
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
221
|
+
else:
|
222
|
+
print("❌ Proxy configuration failed or was cancelled.")
|
223
|
+
else:
|
224
|
+
# Use direct Modal API for sandbox
|
225
|
+
print("🚀 Creating sandbox...")
|
226
|
+
if check_modal_auth():
|
227
|
+
# Import the sandbox creation function
|
228
|
+
from test_modalSandboxScript import create_modal_sandbox
|
229
|
+
result = create_modal_sandbox(
|
230
|
+
args.gpu,
|
231
|
+
repo_url=args.repo_url,
|
232
|
+
repo_name=args.repo_name,
|
233
|
+
volume_name=args.volume_name
|
234
|
+
)
|
235
|
+
if result:
|
236
|
+
print("✅ Sandbox created successfully")
|
237
|
+
else:
|
238
|
+
print("❌ Failed to create sandbox")
|
239
|
+
else:
|
240
|
+
print("❌ Modal authentication failed or was cancelled.")
|
241
|
+
|
242
|
+
elif args.command == "proxy":
|
243
|
+
if args.proxy_command == "configure":
|
244
|
+
# Configure proxy settings
|
245
|
+
from gitarsenal_proxy_client import GitArsenalProxyClient
|
246
|
+
client = GitArsenalProxyClient()
|
247
|
+
client.configure(interactive=True)
|
248
|
+
|
249
|
+
elif args.proxy_command == "status":
|
250
|
+
# Check proxy status
|
251
|
+
from gitarsenal_proxy_client import GitArsenalProxyClient
|
252
|
+
client = GitArsenalProxyClient()
|
253
|
+
response = client.health_check()
|
254
|
+
if response["success"]:
|
255
|
+
print(f"✅ Proxy service is running: {response['data']['message']}")
|
256
|
+
else:
|
257
|
+
print(f"❌ Proxy service health check failed: {response['error']}")
|
258
|
+
|
259
|
+
elif args.proxy_command == "ssh":
|
260
|
+
# Create SSH container through proxy
|
261
|
+
print("🚀 Creating SSH container through proxy...")
|
262
|
+
if check_proxy_config():
|
263
|
+
from gitarsenal_proxy_client import GitArsenalProxyClient
|
264
|
+
client = GitArsenalProxyClient()
|
545
265
|
result = client.create_ssh_container(
|
546
266
|
gpu_type=args.gpu,
|
547
267
|
repo_url=args.repo_url,
|
548
268
|
repo_name=args.repo_name,
|
549
|
-
setup_commands=args.setup_commands,
|
550
269
|
volume_name=args.volume_name,
|
551
270
|
timeout=args.timeout,
|
552
271
|
wait=args.wait
|
553
272
|
)
|
554
|
-
|
555
|
-
|
273
|
+
if result:
|
274
|
+
print("✅ SSH container created successfully through proxy service")
|
275
|
+
print(f"📋 Container ID: {result.get('container_id')}")
|
276
|
+
print(f"🔐 SSH Password: {result.get('ssh_password')}")
|
277
|
+
if not args.wait:
|
278
|
+
print("\n⚠️ Container creation is asynchronous. Use --wait flag to wait for it to be ready.")
|
279
|
+
print(" You can check the status later using the container ID above.")
|
280
|
+
else:
|
556
281
|
print("❌ Failed to create SSH container through proxy service")
|
557
|
-
return 1
|
558
|
-
|
559
|
-
# Print connection information if available
|
560
|
-
if isinstance(result, dict):
|
561
|
-
if "container_id" in result:
|
562
|
-
print(f"📋 Container ID: {result['container_id']}")
|
563
|
-
if "ssh_password" in result:
|
564
|
-
print(f"🔐 SSH Password: {result['ssh_password']}")
|
565
|
-
|
566
|
-
print("✅ SSH container creation process initiated through proxy service")
|
567
|
-
|
568
|
-
if not args.wait:
|
569
|
-
print("\n⚠️ Container creation is asynchronous. Use --wait flag to wait for it to be ready.")
|
570
|
-
print(" You can check the status later using the container ID above.")
|
571
|
-
|
572
282
|
else:
|
573
|
-
print(
|
574
|
-
proxy_parser.print_help()
|
575
|
-
return 1
|
283
|
+
print("❌ Proxy configuration failed or was cancelled.")
|
576
284
|
|
577
|
-
|
578
|
-
print("❌
|
579
|
-
print("Please make sure gitarsenal_proxy_client.py is in the same directory")
|
580
|
-
return 1
|
581
|
-
except Exception as e:
|
582
|
-
print(f"❌ Error: {e}")
|
583
|
-
return 1
|
285
|
+
else:
|
286
|
+
print("❌ Unknown proxy command. Available commands: configure, status, ssh")
|
584
287
|
|
585
288
|
else:
|
586
|
-
print(f"❌ Unknown command: {args.command}")
|
587
289
|
parser.print_help()
|
588
|
-
return 1
|
589
290
|
|
590
291
|
return 0
|
591
292
|
|
@@ -211,6 +211,7 @@ def create_ssh_container():
|
|
211
211
|
try:
|
212
212
|
# Set the token directly in environment
|
213
213
|
os.environ["MODAL_TOKEN_ID"] = MODAL_TOKEN
|
214
|
+
os.environ["MODAL_TOKEN"] = MODAL_TOKEN
|
214
215
|
logger.info(f"Set MODAL_TOKEN_ID in environment (length: {len(MODAL_TOKEN)})")
|
215
216
|
|
216
217
|
# Try to set token via CLI as well
|
@@ -256,8 +257,29 @@ def create_ssh_container():
|
|
256
257
|
try:
|
257
258
|
# Set token in environment for this thread
|
258
259
|
os.environ["MODAL_TOKEN_ID"] = MODAL_TOKEN
|
260
|
+
os.environ["MODAL_TOKEN"] = MODAL_TOKEN
|
259
261
|
logger.info(f"Set MODAL_TOKEN_ID in thread (length: {len(MODAL_TOKEN)})")
|
260
262
|
|
263
|
+
# Create a copy of the environment variables for the container creation
|
264
|
+
env_copy = os.environ.copy()
|
265
|
+
env_copy["MODAL_TOKEN_ID"] = MODAL_TOKEN
|
266
|
+
env_copy["MODAL_TOKEN"] = MODAL_TOKEN
|
267
|
+
|
268
|
+
# Try to set token via CLI again in this thread
|
269
|
+
try:
|
270
|
+
import subprocess
|
271
|
+
subprocess.run(
|
272
|
+
["modal", "token", "set", MODAL_TOKEN],
|
273
|
+
capture_output=True, text=True, check=False
|
274
|
+
)
|
275
|
+
logger.info("Set Modal token via CLI in thread")
|
276
|
+
except Exception as e:
|
277
|
+
logger.warning(f"Failed to set token via CLI in thread: {e}")
|
278
|
+
|
279
|
+
# Explicitly print token status for debugging
|
280
|
+
logger.info(f"MODAL_TOKEN_ID in thread env: {os.environ.get('MODAL_TOKEN_ID')}")
|
281
|
+
logger.info(f"MODAL_TOKEN in thread env: {os.environ.get('MODAL_TOKEN')}")
|
282
|
+
|
261
283
|
result = create_modal_ssh_container(
|
262
284
|
gpu_type,
|
263
285
|
repo_url=repo_url,
|
@@ -2069,26 +2069,40 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
2069
2069
|
|
2070
2070
|
# Check if Modal is authenticated
|
2071
2071
|
try:
|
2072
|
+
# Print all environment variables for debugging
|
2073
|
+
print("🔍 DEBUG: Checking environment variables")
|
2074
|
+
modal_token_id = os.environ.get("MODAL_TOKEN_ID")
|
2075
|
+
modal_token = os.environ.get("MODAL_TOKEN")
|
2076
|
+
print(f"🔍 MODAL_TOKEN_ID exists: {'Yes' if modal_token_id else 'No'}")
|
2077
|
+
print(f"🔍 MODAL_TOKEN exists: {'Yes' if modal_token else 'No'}")
|
2078
|
+
if modal_token_id:
|
2079
|
+
print(f"🔍 MODAL_TOKEN_ID length: {len(modal_token_id)}")
|
2080
|
+
if modal_token:
|
2081
|
+
print(f"🔍 MODAL_TOKEN length: {len(modal_token)}")
|
2082
|
+
|
2072
2083
|
# Try to access Modal token to check authentication
|
2073
2084
|
try:
|
2074
2085
|
# Check if token is set in environment
|
2075
|
-
|
2076
|
-
if not
|
2086
|
+
modal_token_id = os.environ.get("MODAL_TOKEN_ID")
|
2087
|
+
if not modal_token_id:
|
2077
2088
|
print("⚠️ MODAL_TOKEN_ID not found in environment.")
|
2078
2089
|
# Try to get from MODAL_TOKEN
|
2079
2090
|
modal_token = os.environ.get("MODAL_TOKEN")
|
2080
2091
|
if modal_token:
|
2081
2092
|
print("✅ Found token in MODAL_TOKEN environment variable")
|
2082
2093
|
os.environ["MODAL_TOKEN_ID"] = modal_token
|
2094
|
+
modal_token_id = modal_token
|
2095
|
+
print(f"✅ Set MODAL_TOKEN_ID from MODAL_TOKEN (length: {len(modal_token)})")
|
2083
2096
|
|
2084
|
-
if
|
2085
|
-
print(f"✅ Modal token found (length: {len(
|
2097
|
+
if modal_token_id:
|
2098
|
+
print(f"✅ Modal token found (length: {len(modal_token_id)})")
|
2086
2099
|
|
2087
2100
|
# Use the Modal CLI to set the token
|
2088
2101
|
try:
|
2089
2102
|
import subprocess
|
2103
|
+
print(f"🔄 Setting token via Modal CLI (token length: {len(modal_token_id)})")
|
2090
2104
|
result = subprocess.run(
|
2091
|
-
["modal", "token", "set",
|
2105
|
+
["modal", "token", "set", modal_token_id],
|
2092
2106
|
capture_output=True, text=True
|
2093
2107
|
)
|
2094
2108
|
if result.returncode == 0:
|
@@ -2099,20 +2113,51 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
2099
2113
|
print(f"⚠️ Error setting token via CLI: {e}")
|
2100
2114
|
else:
|
2101
2115
|
print("❌ No Modal token found in environment variables")
|
2102
|
-
|
2116
|
+
# Try to get from file as a last resort
|
2117
|
+
try:
|
2118
|
+
home_dir = os.path.expanduser("~")
|
2119
|
+
modal_dir = os.path.join(home_dir, ".modal")
|
2120
|
+
token_file = os.path.join(modal_dir, "token.json")
|
2121
|
+
if os.path.exists(token_file):
|
2122
|
+
print(f"🔍 Found Modal token file at {token_file}")
|
2123
|
+
with open(token_file, 'r') as f:
|
2124
|
+
import json
|
2125
|
+
token_data = json.load(f)
|
2126
|
+
if "token_id" in token_data:
|
2127
|
+
modal_token_id = token_data["token_id"]
|
2128
|
+
os.environ["MODAL_TOKEN_ID"] = modal_token_id
|
2129
|
+
os.environ["MODAL_TOKEN"] = modal_token_id
|
2130
|
+
print(f"✅ Loaded token from file (length: {len(modal_token_id)})")
|
2131
|
+
else:
|
2132
|
+
print("❌ Token file does not contain token_id")
|
2133
|
+
else:
|
2134
|
+
print("❌ Modal token file not found")
|
2135
|
+
except Exception as e:
|
2136
|
+
print(f"❌ Error loading token from file: {e}")
|
2137
|
+
|
2138
|
+
if not os.environ.get("MODAL_TOKEN_ID"):
|
2139
|
+
print("❌ Could not find Modal token in any location")
|
2140
|
+
return None
|
2103
2141
|
|
2104
2142
|
except Exception as e:
|
2105
2143
|
print(f"⚠️ Error checking Modal token: {e}")
|
2106
2144
|
# Try to use the token from environment
|
2107
|
-
|
2108
|
-
|
2145
|
+
modal_token_id = os.environ.get("MODAL_TOKEN_ID")
|
2146
|
+
modal_token = os.environ.get("MODAL_TOKEN")
|
2147
|
+
if modal_token_id:
|
2148
|
+
print(f"🔄 Using MODAL_TOKEN_ID from environment (length: {len(modal_token_id)})")
|
2149
|
+
elif modal_token:
|
2150
|
+
print(f"🔄 Using MODAL_TOKEN from environment (length: {len(modal_token)})")
|
2151
|
+
os.environ["MODAL_TOKEN_ID"] = modal_token
|
2152
|
+
modal_token_id = modal_token
|
2153
|
+
else:
|
2109
2154
|
print("❌ No Modal token available. Cannot proceed.")
|
2110
2155
|
return None
|
2111
2156
|
|
2112
|
-
print(f"🔄 Using Modal token from environment (length: {len(modal_token)})")
|
2113
2157
|
# Set it in both environment variables
|
2114
|
-
os.environ["MODAL_TOKEN_ID"] =
|
2115
|
-
os.environ["MODAL_TOKEN"] =
|
2158
|
+
os.environ["MODAL_TOKEN_ID"] = modal_token_id
|
2159
|
+
os.environ["MODAL_TOKEN"] = modal_token_id
|
2160
|
+
print("✅ Set both MODAL_TOKEN_ID and MODAL_TOKEN environment variables")
|
2116
2161
|
except Exception as e:
|
2117
2162
|
print(f"⚠️ Error checking Modal authentication: {e}")
|
2118
2163
|
print("Continuing anyway, but Modal operations may fail")
|