portacode 1.4.15.dev9__py3-none-any.whl → 1.4.15.dev11__py3-none-any.whl

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.
portacode/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '1.4.15.dev9'
32
- __version_tuple__ = version_tuple = (1, 4, 15, 'dev9')
31
+ __version__ = version = '1.4.15.dev11'
32
+ __version_tuple__ = version_tuple = (1, 4, 15, 'dev11')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -47,9 +47,7 @@ UNIT_DIR = Path("/etc/systemd/system")
47
47
  _MANAGED_CONTAINERS_CACHE_TTL_S = 30.0
48
48
  _MANAGED_CONTAINERS_CACHE: Dict[str, Any] = {"timestamp": 0.0, "summary": None}
49
49
  _MANAGED_CONTAINERS_CACHE_LOCK = threading.Lock()
50
- _STARTUP_TEMPLATES: List[str] | None = None
51
- _STARTUP_TEMPLATE_KEY: tuple[Any, ...] | None = None
52
- _STARTUP_TEMPLATES_LOCK = threading.Lock()
50
+ _STARTUP_TEMPLATES_REFRESHED = False
53
51
 
54
52
  ProgressCallback = Callable[[int, int, Dict[str, Any], str, Optional[Dict[str, Any]]], None]
55
53
 
@@ -182,16 +180,6 @@ def _list_templates(client: Any, node: str, storages: Iterable[Dict[str, Any]])
182
180
  return templates
183
181
 
184
182
 
185
- def _template_key(config: Dict[str, Any]) -> tuple[Any, ...]:
186
- return (
187
- config.get("host"),
188
- config.get("node"),
189
- config.get("user"),
190
- config.get("token_name"),
191
- config.get("verify_ssl"),
192
- )
193
-
194
-
195
183
  def _build_proxmox_client_from_config(config: Dict[str, Any]):
196
184
  user = config.get("user")
197
185
  token_name = config.get("token_name")
@@ -209,41 +197,22 @@ def _build_proxmox_client_from_config(config: Dict[str, Any]):
209
197
  )
210
198
 
211
199
 
212
- def _ensure_startup_templates(config: Dict[str, Any]) -> None:
213
- global _STARTUP_TEMPLATES, _STARTUP_TEMPLATE_KEY
214
- if not config:
215
- with _STARTUP_TEMPLATES_LOCK:
216
- _STARTUP_TEMPLATES = []
217
- _STARTUP_TEMPLATE_KEY = None
200
+ def _ensure_templates_refreshed_on_startup(config: Dict[str, Any]) -> None:
201
+ global _STARTUP_TEMPLATES_REFRESHED
202
+ if _STARTUP_TEMPLATES_REFRESHED or not config or not config.get("token_value"):
203
+ _STARTUP_TEMPLATES_REFRESHED = True
218
204
  return
219
- with _STARTUP_TEMPLATES_LOCK:
220
- if _STARTUP_TEMPLATE_KEY == _template_key(config) and _STARTUP_TEMPLATES is not None:
221
- return
222
- key = _template_key(config)
223
- templates: List[str] = []
224
205
  try:
225
206
  client = _build_proxmox_client_from_config(config)
226
207
  node = config.get("node") or _pick_node(client)
227
208
  storages = client.nodes(node).storage.get()
228
209
  templates = _list_templates(client, node, storages)
210
+ if templates:
211
+ config["templates"] = templates
229
212
  except Exception as exc:
230
- logger.warning("Unable to refresh Proxmox templates: %s", exc)
231
- with _STARTUP_TEMPLATES_LOCK:
232
- _STARTUP_TEMPLATES = list(templates)
233
- _STARTUP_TEMPLATE_KEY = key
234
-
235
-
236
- def _get_startup_templates(config: Dict[str, Any]) -> List[str]:
237
- _ensure_startup_templates(config)
238
- with _STARTUP_TEMPLATES_LOCK:
239
- return list(_STARTUP_TEMPLATES or [])
240
-
241
-
242
- def _clear_startup_templates() -> None:
243
- global _STARTUP_TEMPLATES, _STARTUP_TEMPLATE_KEY
244
- with _STARTUP_TEMPLATES_LOCK:
245
- _STARTUP_TEMPLATES = None
246
- _STARTUP_TEMPLATE_KEY = None
213
+ logger.warning("Unable to refresh Proxmox templates on startup: %s", exc)
214
+ finally:
215
+ _STARTUP_TEMPLATES_REFRESHED = True
247
216
 
248
217
 
249
218
  def _pick_storage(storages: Iterable[Dict[str, Any]]) -> str:
@@ -756,7 +725,7 @@ def _remove_container_record(vmid: int) -> None:
756
725
 
757
726
 
758
727
  def _build_container_payload(message: Dict[str, Any], config: Dict[str, Any]) -> Dict[str, Any]:
759
- templates = _get_startup_templates(config)
728
+ templates = config.get("templates") or []
760
729
  default_template = templates[0] if templates else ""
761
730
  template = message.get("template") or default_template
762
731
  if not template:
@@ -1177,6 +1146,7 @@ def build_snapshot(config: Dict[str, Any]) -> Dict[str, Any]:
1177
1146
  }
1178
1147
  if not config:
1179
1148
  return {"configured": False, "network": base_network}
1149
+ _ensure_templates_refreshed_on_startup(config)
1180
1150
  return {
1181
1151
  "configured": True,
1182
1152
  "host": config.get("host"),
@@ -1184,14 +1154,13 @@ def build_snapshot(config: Dict[str, Any]) -> Dict[str, Any]:
1184
1154
  "user": config.get("user"),
1185
1155
  "token_name": config.get("token_name"),
1186
1156
  "default_storage": config.get("default_storage"),
1187
- "templates": _get_startup_templates(config),
1157
+ "templates": config.get("templates") or [],
1188
1158
  "last_verified": config.get("last_verified"),
1189
1159
  "network": base_network,
1190
1160
  }
1191
1161
 
1192
1162
 
1193
1163
  def configure_infrastructure(token_identifier: str, token_value: str, verify_ssl: bool = False) -> Dict[str, Any]:
1194
- _clear_startup_templates()
1195
1164
  ProxmoxAPI = _ensure_proxmoxer()
1196
1165
  user, token_name = _parse_token(token_identifier)
1197
1166
  client = ProxmoxAPI(
@@ -1227,12 +1196,12 @@ def configure_infrastructure(token_identifier: str, token_value: str, verify_ssl
1227
1196
  "token_value": token_value,
1228
1197
  "verify_ssl": verify_ssl,
1229
1198
  "default_storage": default_storage,
1199
+ "templates": templates,
1230
1200
  "last_verified": datetime.utcnow().isoformat() + "Z",
1231
1201
  "network": network,
1232
1202
  "node_status": status,
1233
1203
  }
1234
1204
  _save_config(config)
1235
- _ensure_startup_templates(config)
1236
1205
  snapshot = build_snapshot(config)
1237
1206
  snapshot["node_status"] = status
1238
1207
  snapshot["managed_containers"] = _get_managed_containers_summary(force=True)
@@ -1252,7 +1221,6 @@ def revert_infrastructure() -> Dict[str, Any]:
1252
1221
  _revert_bridge()
1253
1222
  if CONFIG_PATH.exists():
1254
1223
  CONFIG_PATH.unlink()
1255
- _clear_startup_templates()
1256
1224
  snapshot = build_snapshot({})
1257
1225
  snapshot["network"] = snapshot.get("network", {})
1258
1226
  snapshot["network"]["applied"] = False
@@ -1314,7 +1282,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
1314
1282
  device_private_key = (message.get("device_private_key") or "").strip()
1315
1283
  has_device_keypair = bool(device_public_key and device_private_key)
1316
1284
  config_guess = _load_config()
1317
- template_candidates = _get_startup_templates(config_guess)
1285
+ template_candidates = config_guess.get("templates") or []
1318
1286
  template_hint = (message.get("template") or (template_candidates[0] if template_candidates else "")).strip()
1319
1287
  package_manager = _guess_package_manager_from_template(template_hint)
1320
1288
  bootstrap_user, bootstrap_password, bootstrap_ssh_key = _get_provisioning_user_info(message)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: portacode
3
- Version: 1.4.15.dev9
3
+ Version: 1.4.15.dev11
4
4
  Summary: Portacode CLI client and SDK
5
5
  Home-page: https://github.com/portacode/portacode
6
6
  Author: Meena Erian
@@ -1,7 +1,7 @@
1
1
  portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
2
2
  portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
3
3
  portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
4
- portacode/_version.py,sha256=YbH9Im7cDkYWkWFiH-JGJ5BzJGjRVMg1TyCC8DAh1fE,719
4
+ portacode/_version.py,sha256=xmWnbzztE5Rc80b-QMEet19V4hm80qIDp1evukvT-mY,721
5
5
  portacode/cli.py,sha256=mGLKoZ-T2FBF7IA9wUq0zyG0X9__-A1ao7gajjcVRH8,21828
6
6
  portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
7
7
  portacode/keypair.py,sha256=0OO4vHDcF1XMxCDqce61xFTlFwlTcmqe5HyGsXFEt7s,5838
@@ -22,7 +22,7 @@ portacode/connection/handlers/diff_handlers.py,sha256=iYTIRCcpEQ03vIPKZCsMTE5aZb
22
22
  portacode/connection/handlers/file_handlers.py,sha256=nAJH8nXnX07xxD28ngLpgIUzcTuRwZBNpEGEKdRqohw,39507
23
23
  portacode/connection/handlers/project_aware_file_handlers.py,sha256=AqgMnDqX2893T2NsrvUSCwjN5VKj4Pb2TN0S_SuboOE,9803
24
24
  portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
25
- portacode/connection/handlers/proxmox_infra.py,sha256=g3AXQ_SQ5-WDH0ixDMtowqPtod6ruTrPd7_6FkMp1ts,68206
25
+ portacode/connection/handlers/proxmox_infra.py,sha256=GX2IE1J0YX5GHnqqn__e_wpag_Lsa-cWVRQ82MZnbjU,67267
26
26
  portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
27
27
  portacode/connection/handlers/session.py,sha256=uNGfiO_1B9-_yjJKkpvmbiJhIl6b-UXlT86UTfd6WYE,42219
28
28
  portacode/connection/handlers/system_handlers.py,sha256=fr12QpOr_Z8KYGUU-AYrTQwRPAcrLK85hvj3SEq1Kw8,14757
@@ -65,7 +65,7 @@ portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,3
65
65
  portacode/utils/diff_apply.py,sha256=4Oi7ft3VUCKmiUE4VM-OeqO7Gk6H7PF3WnN4WHXtjxI,15157
66
66
  portacode/utils/diff_renderer.py,sha256=S76StnQ2DLfsz4Gg0m07UwPfRp8270PuzbNaQq-rmYk,13850
67
67
  portacode/utils/ntp_clock.py,sha256=VqCnWCTehCufE43W23oB-WUdAZGeCcLxkmIOPwInYHc,2499
68
- portacode-1.4.15.dev9.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
68
+ portacode-1.4.15.dev11.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
69
69
  test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
70
70
  test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
71
71
  test_modules/test_device_online.py,sha256=QtYq0Dq9vME8Gp2O4fGSheqVf8LUtpsSKosXXk56gGM,1654
@@ -91,8 +91,8 @@ testing_framework/core/playwright_manager.py,sha256=Tw46qwxIhOFkS48C2IWIQHHNpEe-
91
91
  testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
92
92
  testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
93
93
  testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
94
- portacode-1.4.15.dev9.dist-info/METADATA,sha256=6lnCia50lWblHLbiGKsxzaOVohX8yzayZgrAB8Hz-CY,13051
95
- portacode-1.4.15.dev9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
96
- portacode-1.4.15.dev9.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
97
- portacode-1.4.15.dev9.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
98
- portacode-1.4.15.dev9.dist-info/RECORD,,
94
+ portacode-1.4.15.dev11.dist-info/METADATA,sha256=YjU_cRf0I5P6zz-KmGOslg3APj4CL8IgOHbP13Z6T1U,13052
95
+ portacode-1.4.15.dev11.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
96
+ portacode-1.4.15.dev11.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
97
+ portacode-1.4.15.dev11.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
98
+ portacode-1.4.15.dev11.dist-info/RECORD,,