withcache 0.13.1__tar.gz → 0.13.2__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.
Files changed (49) hide show
  1. {withcache-0.13.1 → withcache-0.13.2}/PKG-INFO +1 -1
  2. {withcache-0.13.1 → withcache-0.13.2}/shim/build.zig.zon +1 -1
  3. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/__init__.py +1 -1
  4. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_api.py +14 -3
  5. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/client.py +4 -1
  6. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/server.py +21 -8
  7. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_catalog_api.py +16 -0
  8. {withcache-0.13.1 → withcache-0.13.2}/.gitignore +0 -0
  9. {withcache-0.13.1 → withcache-0.13.2}/LICENSE +0 -0
  10. {withcache-0.13.1 → withcache-0.13.2}/README.md +0 -0
  11. {withcache-0.13.1 → withcache-0.13.2}/deploy/Containerfile +0 -0
  12. {withcache-0.13.1 → withcache-0.13.2}/deploy/compose.local-build.yml +0 -0
  13. {withcache-0.13.1 → withcache-0.13.2}/deploy/compose.yml +0 -0
  14. {withcache-0.13.1 → withcache-0.13.2}/deploy/envvars.example +0 -0
  15. {withcache-0.13.1 → withcache-0.13.2}/hatch_build.py +0 -0
  16. {withcache-0.13.1 → withcache-0.13.2}/pyproject.toml +0 -0
  17. {withcache-0.13.1 → withcache-0.13.2}/shim/build.zig +0 -0
  18. {withcache-0.13.1 → withcache-0.13.2}/shim/shim.zig +0 -0
  19. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_app.py +0 -0
  20. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_events_log.py +0 -0
  21. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_settings_store.py +0 -0
  22. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_shim.py +0 -0
  23. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_table_state.py +0 -0
  24. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/_layout.html +0 -0
  25. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/_table_macros.html +0 -0
  26. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/catalog.html +0 -0
  27. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/dashboard.html +0 -0
  28. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/events.html +0 -0
  29. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/login.html +0 -0
  30. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/misses.html +0 -0
  31. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/_templates/ui/settings.html +0 -0
  32. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/curlwithcache.py +0 -0
  33. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/oras.py +0 -0
  34. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/static/bootstrap-icons.min.css +0 -0
  35. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/static/bootstrap.min.css +0 -0
  36. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/static/fonts/bootstrap-icons.woff +0 -0
  37. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/static/fonts/bootstrap-icons.woff2 +0 -0
  38. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/static/htmx.min.js +0 -0
  39. {withcache-0.13.1 → withcache-0.13.2}/src/withcache/wgetwithcache.py +0 -0
  40. {withcache-0.13.1 → withcache-0.13.2}/tests/test_differential.py +0 -0
  41. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_admin_forms.py +0 -0
  42. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_blob.py +0 -0
  43. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_events.py +0 -0
  44. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_scaffold.py +0 -0
  45. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_settings_persistence.py +0 -0
  46. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_ui_pages.py +0 -0
  47. {withcache-0.13.1 → withcache-0.13.2}/tests/test_fastapi_uvicorn_smoke.py +0 -0
  48. {withcache-0.13.1 → withcache-0.13.2}/tests/test_oras.py +0 -0
  49. {withcache-0.13.1 → withcache-0.13.2}/tests/test_withcache.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: withcache
3
- Version: 0.13.1
3
+ Version: 0.13.2
4
4
  Summary: Operator-curated, URL-keyed artifact cache for a small lab (CUDA/ROCm/DOCA/firmware)
5
5
  Project-URL: Homepage, https://github.com/safl/withcache
6
6
  Author-email: "Simon A. F. Lund" <safl@safl.dk>
@@ -2,7 +2,7 @@
2
2
  .name = .withcache_shim,
3
3
  // Zig requires a literal here; keep it in lockstep with the project's
4
4
  // single source (src/withcache/__init__.py) via `make bump` / `make version-check`.
5
- .version = "0.13.1",
5
+ .version = "0.13.2",
6
6
  .fingerprint = 0xd7d96c5ed212ccaa,
7
7
  .minimum_zig_version = "0.16.0",
8
8
  .paths = .{
@@ -22,6 +22,6 @@ inherit the framework floor.
22
22
  from . import oras
23
23
  from .client import blob_url, cache_base, is_cached, serve_url
24
24
 
25
- __version__ = "0.13.1"
25
+ __version__ = "0.13.2"
26
26
 
27
27
  __all__ = ["__version__", "blob_url", "cache_base", "is_cached", "oras", "serve_url"]
@@ -256,9 +256,19 @@ def register_api_routes(app: FastAPI) -> None:
256
256
  """Insert one catalog entry.
257
257
 
258
258
  Body: ``{"name": "...", "src": "...", "format?", "arch?",
259
- "sha256?", "size_bytes?", "resolved_src?", "description?"}``.
260
- Only ``src`` is required; every other field is optional and
261
- gets persisted through the ``catalog.toml`` round-trip.
259
+ "sha256?", "size_bytes?", "resolved_src?", "description?",
260
+ "netboot_ref?"}``. Only ``src`` is required; every other
261
+ field is optional and gets persisted through the
262
+ ``catalog.toml`` round-trip.
263
+
264
+ ``netboot_ref`` names another catalog entry (by ``name``)
265
+ whose bytes are a nosi netboot bundle (vmlinuz + initrd +
266
+ manifest) that nbdmux extracts at warm time so bty can
267
+ ramboot the image using its own kernel. Present iff the
268
+ entry is a disk image that has a matching netboot bundle;
269
+ the bundle entry itself never carries a ``netboot_ref``.
270
+ Withcache does not validate that the referenced entry
271
+ exists -- the sibling may be added in either order.
262
272
 
263
273
  409 when an entry with the same ``name`` already exists;
264
274
  rejecting on duplicate name (not src) because the display
@@ -278,6 +288,7 @@ def register_api_routes(app: FastAPI) -> None:
278
288
  "sha256",
279
289
  "size_bytes",
280
290
  "description",
291
+ "netboot_ref",
281
292
  }
282
293
  if not isinstance(body, dict):
283
294
  raise HTTPException(status_code=400, detail="body must be a JSON object")
@@ -221,7 +221,10 @@ def add_catalog_entry(
221
221
 
222
222
  ``entry`` must carry at least ``name`` + ``src``. Optional
223
223
  fields: ``format``, ``arch``, ``sha256``, ``size_bytes``,
224
- ``resolved_src``, ``description``.
224
+ ``resolved_src``, ``description``, ``netboot_ref`` (name of
225
+ a sibling entry carrying the matching nosi netboot bundle;
226
+ consumed by nbdmux to serve vmlinuz + initrd alongside the
227
+ disk-image export).
225
228
 
226
229
  Raises :class:`WithcacheError` on any HTTP failure (409 if the
227
230
  entry name already exists; 401 if auth is enabled and no valid
@@ -147,18 +147,31 @@ def _serialise_catalog(entries: list[dict[str, Any]]) -> bytes:
147
147
  row can't smuggle arbitrary TOML through.
148
148
 
149
149
  Scalar keys emitted: ``name``, ``src``, ``resolved_src``,
150
- ``format``, ``arch``, ``sha256``, ``description``. Integer:
151
- ``size_bytes``. ``resolved_src`` is the canonical fetch URL
152
- (for ``oras://`` refs; equal to ``src`` for plain HTTPS);
153
- bty needs it to render iPXE flash chains against the byte
154
- URL directly. ``description`` is operator-supplied prose so
155
- the /ui/images page has something better than the URL to
156
- display.
150
+ ``format``, ``arch``, ``sha256``, ``description``,
151
+ ``netboot_ref``. Integer: ``size_bytes``. ``resolved_src`` is
152
+ the canonical fetch URL (for ``oras://`` refs; equal to
153
+ ``src`` for plain HTTPS); bty needs it to render iPXE flash
154
+ chains against the byte URL directly. ``description`` is
155
+ operator-supplied prose so the /ui/images page has something
156
+ better than the URL to display. ``netboot_ref`` names a
157
+ sibling catalog entry carrying the matching nosi netboot
158
+ bundle (kernel + initrd) so nbdmux can pair the disk image
159
+ with its own kernel at warm time; see the ``add_catalog_entry``
160
+ docstring in ``_api.py`` for the pairing story.
157
161
  """
158
162
  out: list[str] = ["version = 1", ""]
159
163
  for e in entries:
160
164
  out.append("[[images]]")
161
- for key in ("name", "src", "resolved_src", "format", "arch", "sha256", "description"):
165
+ for key in (
166
+ "name",
167
+ "src",
168
+ "resolved_src",
169
+ "format",
170
+ "arch",
171
+ "sha256",
172
+ "description",
173
+ "netboot_ref",
174
+ ):
162
175
  val = e.get(key)
163
176
  if val is None or val == "":
164
177
  continue
@@ -167,12 +167,28 @@ class AddCatalogEntryTests(_CatalogApiBase):
167
167
  "sha256": "b" * 64,
168
168
  "size_bytes": 2048,
169
169
  "description": "Debian sysdev",
170
+ "netboot_ref": "debian-netboot",
170
171
  },
171
172
  )
172
173
  self.assertEqual(r.status_code, 201, r.text)
173
174
  stored = self.catalog.entries[0]
174
175
  self.assertEqual(stored["description"], "Debian sysdev")
175
176
  self.assertEqual(stored["resolved_src"], "https://example/debian.img.gz")
177
+ self.assertEqual(stored["netboot_ref"], "debian-netboot")
178
+
179
+ def test_netboot_ref_persists_through_toml_round_trip(self) -> None:
180
+ """netboot_ref must survive the catalog.toml write-then-reload."""
181
+ self.client.post(
182
+ "/catalog/entries",
183
+ json={
184
+ "name": "debian",
185
+ "src": "https://example/debian.img.gz",
186
+ "netboot_ref": "debian-netboot",
187
+ },
188
+ )
189
+ toml_path = os.path.join(self._tmpdir, "catalog.toml")
190
+ content = open(toml_path, encoding="utf-8").read()
191
+ self.assertIn('netboot_ref = "debian-netboot"', content)
176
192
 
177
193
  def test_add_persists_to_disk(self) -> None:
178
194
  self.client.post(
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes