gitarsenal-cli 1.6.6 → 1.6.9
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__/test_modalSandboxScript_stable.cpython-313.pyc +0 -0
- package/python/fix_modal_token.py +14 -14
- package/python/fix_modal_token_advanced.py +1 -0
- package/python/test_container.py +54 -0
- package/python/test_modal.py +54 -0
- package/python/test_modalSandboxScript.py +14 -6
- package/test_modalSandboxScript.py +14 -6
- package/test_cuda_setup.py +0 -148
package/package.json
CHANGED
@@ -60,19 +60,19 @@ except (ImportError, ValueError) as e:
|
|
60
60
|
# os.environ["MODAL_TOKEN_SECRET"] = TOKEN_SECRET
|
61
61
|
# print(f"✅ Set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables")
|
62
62
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
# Create token file
|
64
|
+
modal_dir = Path.home() / ".modal"
|
65
|
+
modal_dir.mkdir(exist_ok=True)
|
66
|
+
token_file = modal_dir / "token.json"
|
67
|
+
with open(token_file, 'w') as f:
|
68
|
+
f.write(f'{{"token_id": "{TOKEN_ID}", "token_secret": "{TOKEN_SECRET}"}}')
|
69
|
+
print(f"✅ Created token file at {token_file}")
|
70
70
|
|
71
|
-
#
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
71
|
+
# Create .modalconfig file
|
72
|
+
modalconfig_file = Path.home() / ".modalconfig"
|
73
|
+
with open(modalconfig_file, 'w') as f:
|
74
|
+
f.write(f"token_id = {TOKEN_ID}\n")
|
75
|
+
f.write(f"token_secret = {TOKEN_SECRET}\n")
|
76
|
+
print(f"✅ Created .modalconfig file at {modalconfig_file}")
|
77
77
|
|
78
|
-
|
78
|
+
print("\n✅ Done fixing Modal token. Please try your command again.")
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import subprocess
|
2
|
+
import time
|
3
|
+
import secrets
|
4
|
+
import string
|
5
|
+
import modal
|
6
|
+
|
7
|
+
def generate_random_password(length=16):
|
8
|
+
"""Generate a random password for SSH access"""
|
9
|
+
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
10
|
+
password = ''.join(secrets.choice(alphabet) for i in range(length))
|
11
|
+
return password
|
12
|
+
|
13
|
+
image = (
|
14
|
+
modal.Image.from_registry("nvidia/cuda:12.4.0-devel-ubuntu22.04", add_python="3.11")
|
15
|
+
.apt_install("openssh-server", "sudo", "curl", "wget", "git", "vim", "htop", "tmux", "nvtop")
|
16
|
+
.pip_install("cupy-cuda12x", "torch", "transformers")
|
17
|
+
.run_commands(
|
18
|
+
"mkdir -p /var/run/sshd",
|
19
|
+
"ssh-keygen -A",
|
20
|
+
"sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config",
|
21
|
+
"sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config",
|
22
|
+
"echo 'export PATH=/usr/local/cuda/bin:$PATH' >> /root/.bashrc"
|
23
|
+
)
|
24
|
+
)
|
25
|
+
|
26
|
+
app = modal.App("cuda-ssh-container", image=image)
|
27
|
+
|
28
|
+
@app.function(gpu="A10G", timeout=3600)
|
29
|
+
def start_ssh():
|
30
|
+
# Generate SSH password
|
31
|
+
password = generate_random_password()
|
32
|
+
subprocess.run(["bash", "-c", f"echo 'root:{password}' | chpasswd"], check=True)
|
33
|
+
|
34
|
+
# Start SSH server
|
35
|
+
subprocess.Popen(["/usr/sbin/sshd", "-D"])
|
36
|
+
time.sleep(2)
|
37
|
+
|
38
|
+
# Test CUDA
|
39
|
+
subprocess.run(["nvidia-smi"])
|
40
|
+
subprocess.run(["nvcc", "--version"])
|
41
|
+
|
42
|
+
# Forward SSH port
|
43
|
+
with modal.forward(port=22, unencrypted=True) as tunnel:
|
44
|
+
hostname, port = tunnel.tcp_socket
|
45
|
+
print(f"SSH: ssh -p {port} root@{hostname}")
|
46
|
+
print(f"Password: {password}")
|
47
|
+
|
48
|
+
# Keep alive
|
49
|
+
while True:
|
50
|
+
time.sleep(60)
|
51
|
+
|
52
|
+
if __name__ == "__main__":
|
53
|
+
with app.run():
|
54
|
+
start_ssh.remote()
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import subprocess
|
2
|
+
import time
|
3
|
+
import secrets
|
4
|
+
import string
|
5
|
+
import modal
|
6
|
+
|
7
|
+
def generate_random_password(length=16):
|
8
|
+
"""Generate a random password for SSH access"""
|
9
|
+
alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
|
10
|
+
password = ''.join(secrets.choice(alphabet) for i in range(length))
|
11
|
+
return password
|
12
|
+
|
13
|
+
image = (
|
14
|
+
modal.Image.from_registry("nvidia/cuda:12.4.0-devel-ubuntu22.04", add_python="3.11")
|
15
|
+
.apt_install("openssh-server", "sudo", "curl", "wget", "git", "vim", "htop", "tmux", "nvtop")
|
16
|
+
.pip_install("cupy-cuda12x", "torch", "transformers")
|
17
|
+
.run_commands(
|
18
|
+
"mkdir -p /var/run/sshd",
|
19
|
+
"ssh-keygen -A",
|
20
|
+
"sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config",
|
21
|
+
"sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config",
|
22
|
+
"echo 'export PATH=/usr/local/cuda/bin:$PATH' >> /root/.bashrc"
|
23
|
+
)
|
24
|
+
)
|
25
|
+
|
26
|
+
app = modal.App("cuda-ssh-container", image=image)
|
27
|
+
|
28
|
+
@app.function(gpu="A10G", timeout=3600)
|
29
|
+
def start_ssh():
|
30
|
+
# Generate SSH password
|
31
|
+
password = generate_random_password()
|
32
|
+
subprocess.run(["bash", "-c", f"echo 'root:{password}' | chpasswd"], check=True)
|
33
|
+
|
34
|
+
# Start SSH server
|
35
|
+
subprocess.Popen(["/usr/sbin/sshd", "-D"])
|
36
|
+
time.sleep(2)
|
37
|
+
|
38
|
+
# Test CUDA
|
39
|
+
subprocess.run(["nvidia-smi"])
|
40
|
+
subprocess.run(["nvcc", "--version"])
|
41
|
+
|
42
|
+
# Forward SSH port
|
43
|
+
with modal.forward(port=22, unencrypted=True) as tunnel:
|
44
|
+
hostname, port = tunnel.tcp_socket
|
45
|
+
print(f"SSH: ssh -p {port} root@{hostname}")
|
46
|
+
print(f"Password: {password}")
|
47
|
+
|
48
|
+
# Keep alive
|
49
|
+
while True:
|
50
|
+
time.sleep(60)
|
51
|
+
|
52
|
+
if __name__ == "__main__":
|
53
|
+
with app.run():
|
54
|
+
start_ssh.remote()
|
@@ -1183,15 +1183,16 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
1183
1183
|
# Create SSH-enabled image
|
1184
1184
|
try:
|
1185
1185
|
print("📦 Building SSH-enabled image...")
|
1186
|
+
|
1187
|
+
# Use a more stable CUDA base image and avoid problematic packages
|
1186
1188
|
ssh_image = (
|
1187
|
-
|
1188
|
-
modal.Image.debian_slim()
|
1189
|
+
modal.Image.from_registry("nvidia/cuda:12.4.0-runtime-ubuntu22.04", add_python="3.11")
|
1189
1190
|
.apt_install(
|
1190
1191
|
"openssh-server", "sudo", "curl", "wget", "vim", "htop", "git",
|
1191
1192
|
"python3", "python3-pip", "build-essential", "tmux", "screen", "nano",
|
1192
1193
|
"gpg", "ca-certificates", "software-properties-common"
|
1193
1194
|
)
|
1194
|
-
.pip_install("uv", "modal", "requests", "openai") #
|
1195
|
+
.pip_install("uv", "modal", "requests", "openai") # Remove problematic CUDA packages
|
1195
1196
|
.run_commands(
|
1196
1197
|
# Create SSH directory
|
1197
1198
|
"mkdir -p /var/run/sshd",
|
@@ -1223,14 +1224,21 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
1223
1224
|
volumes_config = {}
|
1224
1225
|
if volume:
|
1225
1226
|
volumes_config[volume_mount_path] = volume
|
1227
|
+
|
1228
|
+
# Create app with image passed directly (THIS IS THE KEY CHANGE)
|
1229
|
+
try:
|
1230
|
+
print("🔍 Testing app creation...")
|
1231
|
+
app = modal.App(app_name, image=ssh_image) # Pass image here
|
1232
|
+
print("✅ Created app successfully")
|
1233
|
+
except Exception as e:
|
1234
|
+
print(f"❌ Error creating app: {e}")
|
1235
|
+
return None
|
1226
1236
|
|
1227
|
-
# Define the SSH container function
|
1237
|
+
# Define the SSH container function (remove image from decorator)
|
1228
1238
|
@app.function(
|
1229
|
-
image=ssh_image,
|
1230
1239
|
timeout=timeout_minutes * 60, # Convert to seconds
|
1231
1240
|
gpu=gpu_spec['gpu'],
|
1232
1241
|
cpu=2,
|
1233
|
-
memory=8192,
|
1234
1242
|
serialized=True,
|
1235
1243
|
volumes=volumes_config if volumes_config else None,
|
1236
1244
|
)
|
@@ -1183,15 +1183,16 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
1183
1183
|
# Create SSH-enabled image
|
1184
1184
|
try:
|
1185
1185
|
print("📦 Building SSH-enabled image...")
|
1186
|
+
|
1187
|
+
# Use a more stable CUDA base image and avoid problematic packages
|
1186
1188
|
ssh_image = (
|
1187
|
-
|
1188
|
-
modal.Image.debian_slim()
|
1189
|
+
modal.Image.from_registry("nvidia/cuda:12.4.0-runtime-ubuntu22.04", add_python="3.11")
|
1189
1190
|
.apt_install(
|
1190
1191
|
"openssh-server", "sudo", "curl", "wget", "vim", "htop", "git",
|
1191
1192
|
"python3", "python3-pip", "build-essential", "tmux", "screen", "nano",
|
1192
1193
|
"gpg", "ca-certificates", "software-properties-common"
|
1193
1194
|
)
|
1194
|
-
.pip_install("uv", "modal", "requests", "openai") #
|
1195
|
+
.pip_install("uv", "modal", "requests", "openai") # Remove problematic CUDA packages
|
1195
1196
|
.run_commands(
|
1196
1197
|
# Create SSH directory
|
1197
1198
|
"mkdir -p /var/run/sshd",
|
@@ -1223,14 +1224,21 @@ def create_modal_ssh_container(gpu_type, repo_url=None, repo_name=None, setup_co
|
|
1223
1224
|
volumes_config = {}
|
1224
1225
|
if volume:
|
1225
1226
|
volumes_config[volume_mount_path] = volume
|
1227
|
+
|
1228
|
+
# Create app with image passed directly (THIS IS THE KEY CHANGE)
|
1229
|
+
try:
|
1230
|
+
print("🔍 Testing app creation...")
|
1231
|
+
app = modal.App(app_name, image=ssh_image) # Pass image here
|
1232
|
+
print("✅ Created app successfully")
|
1233
|
+
except Exception as e:
|
1234
|
+
print(f"❌ Error creating app: {e}")
|
1235
|
+
return None
|
1226
1236
|
|
1227
|
-
# Define the SSH container function
|
1237
|
+
# Define the SSH container function (remove image from decorator)
|
1228
1238
|
@app.function(
|
1229
|
-
image=ssh_image,
|
1230
1239
|
timeout=timeout_minutes * 60, # Convert to seconds
|
1231
1240
|
gpu=gpu_spec['gpu'],
|
1232
1241
|
cpu=2,
|
1233
|
-
memory=8192,
|
1234
1242
|
serialized=True,
|
1235
1243
|
volumes=volumes_config if volumes_config else None,
|
1236
1244
|
)
|
package/test_cuda_setup.py
DELETED
@@ -1,148 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Test script to verify CUDA setup in GitArsenal containers
|
4
|
-
"""
|
5
|
-
|
6
|
-
import subprocess
|
7
|
-
import sys
|
8
|
-
import os
|
9
|
-
|
10
|
-
def test_cuda_basic():
|
11
|
-
"""Test basic CUDA functionality"""
|
12
|
-
print("🧪 Testing basic CUDA functionality...")
|
13
|
-
|
14
|
-
try:
|
15
|
-
# Test nvidia-smi
|
16
|
-
result = subprocess.run(["nvidia-smi"], capture_output=True, text=True, timeout=30)
|
17
|
-
if result.returncode == 0:
|
18
|
-
print("✅ nvidia-smi working")
|
19
|
-
print(f"Output: {result.stdout[:200]}...")
|
20
|
-
else:
|
21
|
-
print(f"❌ nvidia-smi failed: {result.stderr}")
|
22
|
-
return False
|
23
|
-
|
24
|
-
# Test nvcc
|
25
|
-
result = subprocess.run(["nvcc", "--version"], capture_output=True, text=True, timeout=30)
|
26
|
-
if result.returncode == 0:
|
27
|
-
print("✅ nvcc available")
|
28
|
-
print(f"Version: {result.stdout.split('release')[0].strip()}")
|
29
|
-
else:
|
30
|
-
print(f"❌ nvcc failed: {result.stderr}")
|
31
|
-
return False
|
32
|
-
|
33
|
-
return True
|
34
|
-
|
35
|
-
except subprocess.TimeoutExpired:
|
36
|
-
print("❌ CUDA test timed out")
|
37
|
-
return False
|
38
|
-
except Exception as e:
|
39
|
-
print(f"❌ CUDA test error: {e}")
|
40
|
-
return False
|
41
|
-
|
42
|
-
def test_cupy_import():
|
43
|
-
"""Test cupy import"""
|
44
|
-
print("🧪 Testing cupy import...")
|
45
|
-
|
46
|
-
try:
|
47
|
-
import cupy as cp
|
48
|
-
print("✅ cupy imported successfully")
|
49
|
-
|
50
|
-
# Test basic cupy functionality
|
51
|
-
x = cp.array([1, 2, 3, 4, 5])
|
52
|
-
y = cp.square(x)
|
53
|
-
print(f"✅ cupy basic operation: {y}")
|
54
|
-
|
55
|
-
return True
|
56
|
-
|
57
|
-
except ImportError as e:
|
58
|
-
print(f"❌ cupy import failed: {e}")
|
59
|
-
return False
|
60
|
-
except Exception as e:
|
61
|
-
print(f"❌ cupy test error: {e}")
|
62
|
-
return False
|
63
|
-
|
64
|
-
def test_gpu_environment():
|
65
|
-
"""Test GPU environment variables"""
|
66
|
-
print("🧪 Testing GPU environment variables...")
|
67
|
-
|
68
|
-
gpu_vars = {
|
69
|
-
'CUDA_VISIBLE_DEVICES': '0',
|
70
|
-
'NVIDIA_VISIBLE_DEVICES': 'all',
|
71
|
-
'NVIDIA_DRIVER_CAPABILITIES': 'compute,utility'
|
72
|
-
}
|
73
|
-
|
74
|
-
for var, value in gpu_vars.items():
|
75
|
-
os.environ[var] = value
|
76
|
-
print(f"✅ Set {var}={value}")
|
77
|
-
|
78
|
-
# Verify they're set
|
79
|
-
for var, expected_value in gpu_vars.items():
|
80
|
-
actual_value = os.environ.get(var)
|
81
|
-
if actual_value == expected_value:
|
82
|
-
print(f"✅ {var} correctly set to {actual_value}")
|
83
|
-
else:
|
84
|
-
print(f"❌ {var} not set correctly. Expected: {expected_value}, Got: {actual_value}")
|
85
|
-
return False
|
86
|
-
|
87
|
-
return True
|
88
|
-
|
89
|
-
def test_modal_cuda_image():
|
90
|
-
"""Test Modal CUDA image creation"""
|
91
|
-
print("🧪 Testing Modal CUDA image creation...")
|
92
|
-
|
93
|
-
try:
|
94
|
-
import modal
|
95
|
-
|
96
|
-
# Test the same image configuration as the SSH container
|
97
|
-
image = (
|
98
|
-
modal.Image.from_registry("nvidia/cuda:12.4.0-devel-ubuntu22.04", add_python="3.11")
|
99
|
-
.pip_install("cupy-cuda12x", "setuptools", "uv", "modal", "requests", "openai")
|
100
|
-
)
|
101
|
-
|
102
|
-
print("✅ Modal CUDA image created successfully")
|
103
|
-
return True
|
104
|
-
|
105
|
-
except ImportError as e:
|
106
|
-
print(f"❌ Modal import failed: {e}")
|
107
|
-
return False
|
108
|
-
except Exception as e:
|
109
|
-
print(f"❌ Modal CUDA image creation failed: {e}")
|
110
|
-
return False
|
111
|
-
|
112
|
-
def main():
|
113
|
-
"""Run all CUDA tests"""
|
114
|
-
print("🧪 GitArsenal CUDA Setup Tests")
|
115
|
-
print("=" * 50)
|
116
|
-
|
117
|
-
tests = [
|
118
|
-
("GPU Environment", test_gpu_environment),
|
119
|
-
("Modal CUDA Image", test_modal_cuda_image),
|
120
|
-
("Basic CUDA", test_cuda_basic),
|
121
|
-
("Cupy Import", test_cupy_import),
|
122
|
-
]
|
123
|
-
|
124
|
-
passed = 0
|
125
|
-
total = len(tests)
|
126
|
-
|
127
|
-
for test_name, test_func in tests:
|
128
|
-
print(f"\n🔍 Running: {test_name}")
|
129
|
-
try:
|
130
|
-
if test_func():
|
131
|
-
passed += 1
|
132
|
-
print(f"✅ {test_name} PASSED")
|
133
|
-
else:
|
134
|
-
print(f"❌ {test_name} FAILED")
|
135
|
-
except Exception as e:
|
136
|
-
print(f"❌ {test_name} ERROR: {e}")
|
137
|
-
|
138
|
-
print(f"\n📊 Test Results: {passed}/{total} tests passed")
|
139
|
-
|
140
|
-
if passed == total:
|
141
|
-
print("🎉 All CUDA tests passed! The SSH container should work correctly.")
|
142
|
-
return 0
|
143
|
-
else:
|
144
|
-
print("⚠️ Some CUDA tests failed. The SSH container may have issues.")
|
145
|
-
return 1
|
146
|
-
|
147
|
-
if __name__ == "__main__":
|
148
|
-
sys.exit(main())
|