Storage pool management, a beta-test fix pass, and the published docs site - #36
Merged
Merged
Conversation
…ole hook; correct the roles note
…nd hostname-named pools
…w; allow re-registering a removed pool's class
…t accounting, and rebuild the docs site
| row.provisioned_at = self.now | ||
| elif row.cluster_id != cluster_id: | ||
| log.warning("volume_sync: %s reported from %s but its data lives on %s; ignoring", | ||
| row.id, cluster_id, row.cluster_id) |
| if cluster_id is not None: | ||
| node_q = node_q.where(GpuNode.cluster_id == cluster_id) | ||
| node = (await db.execute(node_q.limit(1))).scalar_one_or_none() | ||
| hostname = ev.node_id |
| if node is None: | ||
| # No dangling FK row for a node the ledger does not know; the signal is still logged. | ||
| log.warning("node health event for unknown node=%s cluster=%s kind=%s action=%s", | ||
| ev.node_id, cluster_id, ev.kind, ev.action) |
| if node is None: | ||
| # No dangling FK row for a node the ledger does not know; the signal is still logged. | ||
| log.warning("node health event for unknown node=%s cluster=%s kind=%s action=%s", | ||
| ev.node_id, cluster_id, ev.kind, ev.action) |
| if node is None: | ||
| # No dangling FK row for a node the ledger does not know; the signal is still logged. | ||
| log.warning("node health event for unknown node=%s cluster=%s kind=%s action=%s", | ||
| ev.node_id, cluster_id, ev.kind, ev.action) |
| if node is None: | ||
| # No dangling FK row for a node the ledger does not know; the signal is still logged. | ||
| log.warning("node health event for unknown node=%s cluster=%s kind=%s action=%s", | ||
| ev.node_id, cluster_id, ev.kind, ev.action) |
| async with engine._keyed_atomic(): | ||
| raise _err('duplicate key value violates unique constraint ' | ||
| '"credit_transaction_idempotency_key_key"') | ||
| async with engine._keyed_atomic(): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This branch carries five commits against main: 265 files, +9982 / -3767.
Storage pools and volume placement
Registering a storage pool was API-only. The admin console now has a Storage pools tab under Volumes: register, edit and deregister a pool without curl. A pool linked to a node is always named after that node's hostname, enforced server-side; only a node-less appliance takes a typed name.
Volumes now record the cluster and StorageClass they were provisioned on (alembic 0063), so the admin list and the user's mount panel both say where a volume's data actually lives. The dashboard's storage tile leads with the fleet total and breaks it down per pool underneath.
Beta-test fix pass
A systematic pass over money, permissions and the API/operator contract. 62 findings, 55 fixed and verified, each with a regression test that fails before the fix and passes after. The highlights:
Tenant isolation. The queue list was fleet-wide to any group admin. Cancelling or reprioritising a groupless session was open across tenants. A group admin could enrol a user from another organization and then suspend, delete or reset that account. Private images and arbitrary storage quotas were readable by anyone. All closed and pinned in test_tenant_isolation.py.
Authorization. Global roles and the forced-password-change flag now come from the database rather than the token, so a demotion takes effect within the principal cache window instead of the token's 24 hours. The query-string token is limited to the SSE routes. The login rate limiter reads the hop a trusted proxy appended rather than the first X-Forwarded-For value, configurable with GSHARE_TRUSTED_PROXY_HOPS. A pending account is no longer disclosed before the password is checked.
Credits. Raising a monthly grant changed the balance without writing a ledger row, so the ledger and the balance disagreed. A failed refill sweep left the month marker in place and skipped that month's refill entirely. A consume arriving after settlement charged a finished session. All three fixed.
Session state and the operator contract. A late running callback for a finished session re-created its allocation and leaked card capacity permanently. stop() released the reservation before asking the operator to tear the pod down, so a failed handoff left the pod running on a card the ledger believed was free. Node health callbacks addressed nodes by hostname while the backend looked them up by id, so cordoning never reached the ledger. Every internal callback is now bound to the cluster its operator token names. The CR re-apply path was failing outright on a content-type the API server rejects for custom resources.
Chart and operator. The operator's service account could read every Secret in the cluster; its informer is now confined to the session namespace and the ClusterRole no longer grants secrets. Job and Pod write permissions moved from a ClusterRole to an infra-namespace Role. The in-cluster data tier got a restricted security context. The shipped NetworkPolicies selected labels nothing ever set, so applying the documented security baseline would have cut every session off from DNS and storage; the operator now stamps those labels and the policies are available as an opt-in chart option.
Tests. The suite ran only on SQLite, which enforces no foreign keys. An opt-in Postgres path (GSHARE_TEST_DATABASE_URL) builds the schema with alembic upgrade head; the suite is green on both, and alembic check now reports no drift. That harness surfaced a real defect: bulk user creation failed on Postgres every time, because the membership insert was ordered before the user insert.
Backend 420 → 513 tests (coverage 66% → 69%), operator +30 tests (controller 3% → 35%), frontend 32 → 49.
Documentation and the site
The Korean guide is rewritten throughout, the landing page is rebuilt around real console screenshots, and a workflow publishes the site to GitHub Pages at https://boanlab.github.io/gshare/. The built output is never committed: the workflow builds from docs/ and website/ and hands the result to Pages.