unitlab 2.3.8__tar.gz → 2.3.10__tar.gz
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.
- {unitlab-2.3.8/src/unitlab.egg-info → unitlab-2.3.10}/PKG-INFO +1 -1
- {unitlab-2.3.8 → unitlab-2.3.10}/setup.py +1 -1
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/client.py +4 -4
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/cloudflare_api_tunnel.py +87 -10
- {unitlab-2.3.8 → unitlab-2.3.10/src/unitlab.egg-info}/PKG-INFO +1 -1
- {unitlab-2.3.8 → unitlab-2.3.10}/LICENSE.md +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/README.md +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/setup.cfg +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/__init__.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/__main__.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/binary_manager.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/exceptions.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/main.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/tunnel_config.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/tunnel_service_token.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab/utils.py +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab.egg-info/SOURCES.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab.egg-info/dependency_links.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab.egg-info/entry_points.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab.egg-info/requires.txt +0 -0
- {unitlab-2.3.8 → unitlab-2.3.10}/src/unitlab.egg-info/top_level.txt +0 -0
@@ -297,10 +297,10 @@ class UnitlabClient:
|
|
297
297
|
self.tunnel_manager = CloudflareTunnel(base_domain, device_id)
|
298
298
|
self.jupyter_url = self.tunnel_manager.jupyter_url
|
299
299
|
self.ssh_url = self.tunnel_manager.ssh_url
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
300
|
+
else:
|
301
|
+
self.tunnel_manager = None
|
302
|
+
self.jupyter_url = f"https://jupyter-{device_id}.{base_domain}"
|
303
|
+
self.ssh_url = f"https://ssh-{device_id}.{base_domain}"
|
304
304
|
|
305
305
|
# Setup signal handlers
|
306
306
|
signal.signal(signal.SIGINT, self._handle_shutdown)
|
@@ -53,16 +53,24 @@ class CloudflareAPITunnel:
|
|
53
53
|
"Content-Type": "application/json"
|
54
54
|
} if self.api_token else {}
|
55
55
|
|
56
|
-
# URLs for services
|
56
|
+
# URLs for services - simplified for Jupyter only
|
57
57
|
self.jupyter_subdomain = f"j{self.clean_device_id}"
|
58
|
-
self.ssh_subdomain = f"s{self.clean_device_id}"
|
59
58
|
self.jupyter_url = f"https://{self.jupyter_subdomain}.{self.base_domain}"
|
59
|
+
|
60
|
+
# Keep SSH URLs for compatibility but they won't work yet
|
61
|
+
self.ssh_subdomain = f"s{self.clean_device_id}"
|
60
62
|
self.ssh_hostname = f"{self.ssh_subdomain}.{self.base_domain}"
|
61
|
-
self.ssh_url = self.ssh_hostname
|
63
|
+
self.ssh_url = self.ssh_hostname
|
62
64
|
|
63
65
|
self.tunnel_process = None
|
64
66
|
self.created_dns_records = []
|
65
|
-
|
67
|
+
|
68
|
+
# Try to initialize binary manager, but don't fail if it doesn't work
|
69
|
+
try:
|
70
|
+
self.binary_manager = CloudflaredBinaryManager()
|
71
|
+
except Exception as e:
|
72
|
+
logger.warning(f"Binary manager initialization failed: {e}")
|
73
|
+
self.binary_manager = None
|
66
74
|
|
67
75
|
def create_dns_records(self):
|
68
76
|
"""
|
@@ -209,14 +217,15 @@ class CloudflareAPITunnel:
|
|
209
217
|
self.create_dns_records()
|
210
218
|
self.update_tunnel_config()
|
211
219
|
|
212
|
-
#
|
213
|
-
cloudflared_path = self.
|
220
|
+
# Ensure cloudflared is available
|
221
|
+
cloudflared_path = self._ensure_cloudflared()
|
222
|
+
if not cloudflared_path:
|
223
|
+
raise RuntimeError("Failed to obtain cloudflared binary")
|
214
224
|
|
215
|
-
# Use
|
216
|
-
#
|
217
|
-
service_token = "
|
225
|
+
# Use service token - simple and reliable
|
226
|
+
# The dashboard must have *.1scan.uz -> localhost:8888 configured
|
227
|
+
service_token = "eyJhIjoiYzkxMTkyYWUyMGE1ZDQzZjY1ZTA4NzU1MGQ4ZGM4OWIiLCJ0IjoiMDc3N2ZjMTAtNDljNC00NzJkLTg2NjEtZjYwZDgwZDYxODRkIiwicyI6Ik9XRTNaak5tTVdVdE1tWTRaUzAwTmpoakxTazBaalF0WXpjek1tSm1ZVGt4WlRRMCJ9"
|
218
228
|
|
219
|
-
# Start tunnel with service token
|
220
229
|
cmd = [
|
221
230
|
cloudflared_path,
|
222
231
|
"tunnel",
|
@@ -269,6 +278,74 @@ class CloudflareAPITunnel:
|
|
269
278
|
self.tunnel_process.wait(timeout=5)
|
270
279
|
print("Tunnel stopped")
|
271
280
|
|
281
|
+
def _ensure_cloudflared(self):
|
282
|
+
"""
|
283
|
+
Ensure cloudflared binary is available
|
284
|
+
Downloads it if necessary
|
285
|
+
"""
|
286
|
+
print("🔍 Checking for cloudflared binary...")
|
287
|
+
|
288
|
+
# Try binary manager first
|
289
|
+
if self.binary_manager:
|
290
|
+
try:
|
291
|
+
path = self.binary_manager.get_binary_path()
|
292
|
+
print(f"✅ Using cloudflared from binary manager: {path}")
|
293
|
+
return path
|
294
|
+
except Exception as e:
|
295
|
+
logger.warning(f"Binary manager failed, will download directly: {e}")
|
296
|
+
|
297
|
+
# Direct download fallback - simplified version
|
298
|
+
import platform
|
299
|
+
import urllib.request
|
300
|
+
|
301
|
+
cache_dir = Path.home() / '.unitlab' / 'bin'
|
302
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
303
|
+
|
304
|
+
cloudflared_path = cache_dir / 'cloudflared'
|
305
|
+
if platform.system() == 'Windows':
|
306
|
+
cloudflared_path = cache_dir / 'cloudflared.exe'
|
307
|
+
|
308
|
+
# If already exists, use it
|
309
|
+
if cloudflared_path.exists():
|
310
|
+
print(f"✅ Using cached cloudflared: {cloudflared_path}")
|
311
|
+
return str(cloudflared_path)
|
312
|
+
|
313
|
+
# Download based on platform
|
314
|
+
system = platform.system().lower()
|
315
|
+
machine = platform.machine().lower()
|
316
|
+
|
317
|
+
print(f"📥 Downloading cloudflared for {system}/{machine}...")
|
318
|
+
|
319
|
+
if system == 'linux':
|
320
|
+
if machine in ['x86_64', 'amd64']:
|
321
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64'
|
322
|
+
elif machine in ['aarch64', 'arm64']:
|
323
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64'
|
324
|
+
else:
|
325
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-386'
|
326
|
+
elif system == 'darwin':
|
327
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-amd64.tgz'
|
328
|
+
elif system == 'windows':
|
329
|
+
url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe'
|
330
|
+
else:
|
331
|
+
raise RuntimeError(f"Unsupported platform: {system}")
|
332
|
+
|
333
|
+
try:
|
334
|
+
# Download the file
|
335
|
+
urllib.request.urlretrieve(url, cloudflared_path)
|
336
|
+
|
337
|
+
# Make executable on Unix
|
338
|
+
if system != 'windows':
|
339
|
+
import stat
|
340
|
+
cloudflared_path.chmod(cloudflared_path.stat().st_mode | stat.S_IEXEC)
|
341
|
+
|
342
|
+
print(f"✅ Downloaded cloudflared to: {cloudflared_path}")
|
343
|
+
return str(cloudflared_path)
|
344
|
+
|
345
|
+
except Exception as e:
|
346
|
+
print(f"❌ Failed to download cloudflared: {e}")
|
347
|
+
raise RuntimeError(f"Could not download cloudflared: {e}")
|
348
|
+
|
272
349
|
def cleanup_dns(self):
|
273
350
|
"""
|
274
351
|
Remove created DNS records (optional cleanup)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|