unitlab 2.3.13__tar.gz → 2.3.14__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unitlab
3
- Version: 2.3.13
3
+ Version: 2.3.14
4
4
  Home-page: https://github.com/teamunitlab/unitlab-sdk
5
5
  Author: Unitlab Inc.
6
6
  Author-email: team@unitlab.ai
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="unitlab",
5
- version="2.3.13",
5
+ version="2.3.14",
6
6
  license="MIT",
7
7
  author="Unitlab Inc.",
8
8
  author_email="team@unitlab.ai",
@@ -64,6 +64,7 @@ class CloudflareAPITunnel:
64
64
 
65
65
  self.tunnel_process = None
66
66
  self.created_dns_records = []
67
+ self.tunnel_config_file = None
67
68
 
68
69
  # Try to initialize binary manager, but don't fail if it doesn't work
69
70
  try:
@@ -252,6 +253,13 @@ class CloudflareAPITunnel:
252
253
  else:
253
254
  print(f"❌ Failed to create tunnel: {create_response.text}")
254
255
  return None
256
+ else:
257
+ # Tunnel exists - update config file in case settings changed
258
+ print(f"♻️ Updating configuration for existing tunnel")
259
+ self._configure_tunnel_routes(existing_tunnel['id'])
260
+
261
+ # Ensure DNS records exist
262
+ self.create_dns_records()
255
263
 
256
264
  return existing_tunnel
257
265
 
@@ -260,28 +268,42 @@ class CloudflareAPITunnel:
260
268
  def _configure_tunnel_routes(self, tunnel_id):
261
269
  """
262
270
  Configure ingress routes for the device tunnel
271
+ The tunnel needs to be configured with a config file, not via API
272
+ So we'll create a config file for it
263
273
  """
264
- config_url = f"{self.api_base}/accounts/{self.account_id}/tunnels/{tunnel_id}/configurations"
265
-
266
- config_data = {
267
- "config": {
268
- "ingress": [
269
- {
270
- "hostname": f"{self.jupyter_subdomain}.{self.base_domain}",
271
- "service": "http://localhost:8888"
272
- },
273
- {
274
- "service": "http_status:404"
274
+ import yaml
275
+
276
+ # Create config file for this tunnel
277
+ config_dir = Path.home() / '.cloudflared'
278
+ config_dir.mkdir(exist_ok=True)
279
+ config_file = config_dir / f'config-{tunnel_id}.yml'
280
+
281
+ config = {
282
+ "tunnel": tunnel_id,
283
+ "credentials-file": str(config_dir / f"{tunnel_id}.json"),
284
+ "ingress": [
285
+ {
286
+ "hostname": f"{self.jupyter_subdomain}.{self.base_domain}",
287
+ "service": "http://localhost:8888",
288
+ "originRequest": {
289
+ "noTLSVerify": True
275
290
  }
276
- ]
277
- }
291
+ },
292
+ {
293
+ "hostname": f"{self.ssh_subdomain}.{self.base_domain}",
294
+ "service": "ssh://localhost:22"
295
+ },
296
+ {
297
+ "service": "http_status:404"
298
+ }
299
+ ]
278
300
  }
279
301
 
280
- response = requests.put(config_url, headers=self.headers, json=config_data)
281
- if response.status_code == 200:
282
- print(f"✅ Configured tunnel routes")
283
- else:
284
- print(f"⚠️ Could not configure routes: {response.status_code}")
302
+ with open(config_file, 'w') as f:
303
+ yaml.dump(config, f)
304
+
305
+ print(f"✅ Created tunnel config: {config_file}")
306
+ self.tunnel_config_file = config_file
285
307
 
286
308
  def _save_tunnel_credentials(self, tunnel_info):
287
309
  """
@@ -372,15 +394,27 @@ class CloudflareAPITunnel:
372
394
  return None
373
395
 
374
396
  if creds_file.exists():
375
- # Run tunnel with credentials file
376
- cmd = [
377
- cloudflared_path,
378
- "tunnel",
379
- "--no-autoupdate",
380
- "--credentials-file", str(creds_file),
381
- "run",
382
- tunnel_id
383
- ]
397
+ # Check if config file exists
398
+ config_file = Path.home() / '.cloudflared' / f'config-{tunnel_id}.yml'
399
+ if config_file.exists():
400
+ # Run tunnel with config file (includes routes)
401
+ cmd = [
402
+ cloudflared_path,
403
+ "tunnel",
404
+ "--no-autoupdate",
405
+ "--config", str(config_file),
406
+ "run"
407
+ ]
408
+ else:
409
+ # Fallback to credentials file only
410
+ cmd = [
411
+ cloudflared_path,
412
+ "tunnel",
413
+ "--no-autoupdate",
414
+ "--credentials-file", str(creds_file),
415
+ "run",
416
+ tunnel_id
417
+ ]
384
418
 
385
419
  self.tunnel_process = subprocess.Popen(
386
420
  cmd,
@@ -418,12 +452,17 @@ class CloudflareAPITunnel:
418
452
  def stop(self):
419
453
  """
420
454
  Stop the tunnel if running
455
+ Note: We keep the tunnel configuration for next run
421
456
  """
422
457
  if self.tunnel_process and self.tunnel_process.poll() is None:
423
458
  print("Stopping tunnel...")
424
459
  self.tunnel_process.terminate()
425
- self.tunnel_process.wait(timeout=5)
460
+ try:
461
+ self.tunnel_process.wait(timeout=5)
462
+ except subprocess.TimeoutExpired:
463
+ self.tunnel_process.kill()
426
464
  print("Tunnel stopped")
465
+ print("ℹ️ Tunnel configuration preserved for next run")
427
466
 
428
467
  def _ensure_cloudflared(self):
429
468
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unitlab
3
- Version: 2.3.13
3
+ Version: 2.3.14
4
4
  Home-page: https://github.com/teamunitlab/unitlab-sdk
5
5
  Author: Unitlab Inc.
6
6
  Author-email: team@unitlab.ai
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes