-
Notifications
You must be signed in to change notification settings - Fork 38
fix(cassandra): publish required service schemas #439
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| CREATE KEYSPACE IF NOT EXISTS nvcf_autoscaler WITH replication = {'class': 'NetworkTopologyStrategy', 'ncp': '${REPLICA_COUNT}' } AND durable_writes = true; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| CREATE ROLE IF NOT EXISTS nvcf_autoscaler_app_access; | ||
| GRANT SELECT, MODIFY on keyspace nvcf_autoscaler to nvcf_autoscaler_app_access; | ||
| GRANT SELECT on keyspace system to nvcf_autoscaler_app_access; | ||
|
|
||
| CREATE ROLE IF NOT EXISTS nvcf_autoscaler_app_v0 with login = true and password = '${SERVICE_ROLE_PASSWORD}'; | ||
|
|
||
| INSERT INTO system_auth.role_members (role, member) VALUES ('nvcf_autoscaler_app_access', 'nvcf_autoscaler_app_v0'); | ||
| UPDATE system_auth.roles SET member_of = member_of + {'nvcf_autoscaler_app_access'} where role = 'nvcf_autoscaler_app_v0'; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| -- Canonical schema for nvcf_autoscaler keyspace. | ||
| -- Pinned to the upstream nvcf_autoscaler schema at migration version 9. | ||
| -- account_id (TEXT) consolidates upstream nca_id_string from migrations 02-09. nca_id UUID dropped (NCA IDs are not UUIDs and the column was unused). | ||
|
Comment on lines
+1
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift Align the schema baseline and design record before publication. The SQL comments describe a column-level schema change, while the design record promises that only replica-count templating changes. Resolve this contradiction by either restoring the archived schema or explicitly approving and documenting the compatibility impact.
📍 Affects 2 files
🤖 Prompt for AI Agents |
||
|
|
||
| -- ============================================================ | ||
| -- Tables | ||
| -- ============================================================ | ||
|
|
||
| -- Functions invoked recently. Rows expire via TTL to track a rolling window. | ||
| CREATE TABLE IF NOT EXISTS nvcf_autoscaler.recently_invoked_functions ( | ||
| function_id UUID, | ||
| function_version_id UUID, | ||
| last_updated_at TIMESTAMP, | ||
| account_id TEXT, | ||
| PRIMARY KEY ((function_id, function_version_id)) | ||
| ) WITH default_time_to_live = 600 | ||
| AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'} | ||
| AND read_repair = 'NONE'; | ||
|
|
||
| -- Historical scaling decisions for recently invoked functions, clustered by time. | ||
| CREATE TABLE IF NOT EXISTS nvcf_autoscaler.recently_invoked_functions_history ( | ||
| function_id UUID, | ||
| function_version_id UUID, | ||
| last_updated_at TIMESTAMP, | ||
| account_id TEXT STATIC, | ||
| num_workers INT STATIC, | ||
| last_predicted_desired_instance_count INT, | ||
| last_predicted_error_code TEXT, | ||
| PRIMARY KEY ((function_id, function_version_id), last_updated_at) | ||
| ) WITH CLUSTERING ORDER BY (last_updated_at DESC) | ||
| AND default_time_to_live = 172800 | ||
| AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'} | ||
| AND read_repair = 'NONE'; | ||
|
|
||
| -- Functions with running workers but no recent invocations. | ||
| CREATE TABLE IF NOT EXISTS nvcf_autoscaler.running_functions_without_invocations ( | ||
| function_id UUID, | ||
| function_version_id UUID, | ||
| last_updated_at TIMESTAMP, | ||
| account_id TEXT, | ||
| PRIMARY KEY ((function_id, function_version_id)) | ||
| ) WITH default_time_to_live = 600 | ||
| AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'} | ||
| AND read_repair = 'NONE'; | ||
|
|
||
| -- Historical scaling decisions for running functions without invocations, clustered by time. | ||
| CREATE TABLE IF NOT EXISTS nvcf_autoscaler.running_functions_without_invocations_history ( | ||
| function_id UUID, | ||
| function_version_id UUID, | ||
| last_updated_at TIMESTAMP, | ||
| account_id TEXT STATIC, | ||
| num_workers INT STATIC, | ||
| last_predicted_desired_instance_count INT, | ||
| last_predicted_error_code TEXT, | ||
| PRIMARY KEY ((function_id, function_version_id), last_updated_at) | ||
| ) WITH CLUSTERING ORDER BY (last_updated_at DESC) | ||
| AND default_time_to_live = 172800 | ||
| AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'} | ||
| AND read_repair = 'NONE'; | ||
|
|
||
| -- Distributed lock table for autoscaler leader coordination. | ||
| CREATE TABLE IF NOT EXISTS nvcf_autoscaler.locks ( | ||
| lock_name TEXT PRIMARY KEY, | ||
| node_id TEXT, | ||
| acquired_at TIMESTAMP | ||
| ) WITH default_time_to_live = 3600 | ||
| AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'} | ||
| AND read_repair = 'NONE'; | ||
|
|
||
| -- Liveness registry of autoscaler nodes. Rows expire quickly to reflect health. | ||
| CREATE TABLE IF NOT EXISTS nvcf_autoscaler.healthy_nodes ( | ||
| node_id TEXT PRIMARY KEY, | ||
| last_updated_at TIMESTAMP | ||
| ) WITH default_time_to_live = 180 | ||
| AND compaction = {'class': 'UnifiedCompactionStrategy', 'scaling_parameters': 'T4', 'target_sstable_size': '50MiB', 'base_shard_count': '4', 'expired_sstable_check_frequency_seconds': '300'} | ||
| AND read_repair = 'NONE'; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| CREATE KEYSPACE IF NOT EXISTS nvct_api WITH replication = {'class': 'NetworkTopologyStrategy', 'ncp': '${REPLICA_COUNT}' } AND durable_writes = true; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| CREATE ROLE IF NOT EXISTS nvct_api_app_access; | ||
| GRANT SELECT, MODIFY on keyspace nvct_api to nvct_api_app_access; | ||
| GRANT SELECT on keyspace system to nvct_api_app_access; | ||
|
|
||
| CREATE ROLE IF NOT EXISTS nvct_api_app_v0 with login = true and password = '${SERVICE_ROLE_PASSWORD}'; | ||
|
|
||
| INSERT INTO system_auth.role_members (role, member) VALUES ('nvct_api_app_access', 'nvct_api_app_v0'); | ||
| UPDATE system_auth.roles SET member_of = member_of + {'nvct_api_app_access'} where role = 'nvct_api_app_v0'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| -- Canonical schema for nvct_api keyspace. | ||
| -- Reference: nvcf/nvct-api v1.2.4 local_env/cassandra/schema/0001_initial_schema.cql | ||
|
Comment on lines
+1
to
+2
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate guidance and relevant files
printf '\n== AGENTS files ==\n'
find .. -name AGENTS.md -print
printf '\n== Relevant file listings ==\n'
git ls-files 'migrations/cassandra/keyspaces/**' | sed -n '1,120p'
printf '\n== README pin references ==\n'
rg -n 'nvct_api|v1\.5\.2|v1\.2\.4|nvct-api' migrations/cassandra/keyspaces/README.md migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql || true
printf '\n== File sizes ==\n'
wc -l migrations/cassandra/keyspaces/README.md migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sqlRepository: NVIDIA/nvcf Length of output: 6104 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Read the small relevant sections with line numbers
printf '\n== README excerpt ==\n'
cat -n migrations/cassandra/keyspaces/README.md | sed -n '1,220p'
printf '\n== SQL excerpt ==\n'
cat -n migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql | sed -n '1,220p'Repository: NVIDIA/nvcf Length of output: 10620 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect nearby documentation for how the pinned source revisions are tracked.
rg -n 'v1\.5\.2|v1\.2\.4|nvct_api|schema/0001_initial_schema\.cql|design record|pin' migrations/cassandra/keyspaces -g '!**/*.png'Repository: NVIDIA/nvcf Length of output: 3684 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show the exact README entry and any related design record references.
python3 - <<'PY'
from pathlib import Path
files = [
Path('migrations/cassandra/keyspaces/README.md'),
Path('migrations/cassandra/keyspaces/nvct_api/03_init_tables.up.sql'),
]
for p in files:
print(f"\n### {p} ###")
text = p.read_text()
for i, line in enumerate(text.splitlines(), 1):
if 'nvct_api' in line or 'v1.5.2' in line or 'v1.2.4' in line or 'schema/0001_initial_schema.cql' in line:
start = max(1, i-3)
end = min(len(text.splitlines()), i+3)
for j in range(start, end+1):
print(f"{j}: {text.splitlines()[j-1]}")
print()
PY
printf '\n== search for design record ==\n'
rg -n 'nvct_api|v1\.5\.2|v1\.2\.4|0001_initial_schema\.cql|design record|upstream schema' . -g '!**/.git/**'Repository: NVIDIA/nvcf Length of output: 20276 Update the provenance reference in 🤖 Prompt for AI Agents |
||
|
|
||
| -- ============================================================ | ||
| -- User-Defined Types | ||
| -- ============================================================ | ||
|
|
||
| CREATE TYPE IF NOT EXISTS nvct_api.model_udt ( | ||
| name TEXT, | ||
| version TEXT, | ||
| url TEXT | ||
| ); | ||
|
|
||
| CREATE TYPE IF NOT EXISTS nvct_api.resource_udt ( | ||
| name TEXT, | ||
| version TEXT, | ||
| url TEXT | ||
| ); | ||
|
|
||
| CREATE TYPE IF NOT EXISTS nvct_api.gpu_spec_udt ( | ||
| instance_type TEXT, | ||
| gpu TEXT, | ||
| backend TEXT, | ||
| configuration TEXT, | ||
| clusters FROZEN<SET<TEXT>>, | ||
| regions FROZEN<SET<TEXT>>, | ||
| attributes FROZEN<SET<TEXT>>, | ||
| max_request_concurrency INT, | ||
| helm_validation_policy TEXT | ||
| ); | ||
|
|
||
| CREATE TYPE IF NOT EXISTS nvct_api.health_udt ( | ||
| sis_request_id UUID, | ||
| gpu TEXT, | ||
| backend TEXT, | ||
| instance_type TEXT, | ||
| error TEXT | ||
| ); | ||
|
|
||
| CREATE TYPE IF NOT EXISTS nvct_api.telemetries_udt ( | ||
| logs_telemetry_id UUID, | ||
| metrics_telemetry_id UUID, | ||
| traces_telemetry_id UUID | ||
| ); | ||
|
|
||
| -- ============================================================ | ||
| -- Tables | ||
| -- ============================================================ | ||
|
|
||
| -- Primary task store. Each row is a unique task instance. | ||
| CREATE TABLE IF NOT EXISTS nvct_api.tasks_v2 ( | ||
| nca_id TEXT, | ||
| task_id UUID, | ||
| name TEXT, | ||
| description TEXT, | ||
| tags FROZEN<SET<TEXT>>, | ||
| container_image TEXT, | ||
| container_args TEXT, | ||
| container_environment TEXT, | ||
| models FROZEN<SET<model_udt>>, | ||
| resources FROZEN<SET<resource_udt>>, | ||
| gpu_spec gpu_spec_udt, | ||
| max_runtime_duration DURATION, | ||
| max_queued_duration DURATION, | ||
| terminal_grace_period_duration DURATION, | ||
| result_handling_strategy TEXT, | ||
| helm_chart TEXT, | ||
| results_location TEXT, | ||
| status TEXT, | ||
| telemetries FROZEN<telemetries_udt>, | ||
| health_info FROZEN<health_udt>, | ||
| percent_complete INT, | ||
| last_updated_at TIMESTAMP, | ||
| last_heartbeat_at TIMESTAMP, | ||
| created_at TIMESTAMP, | ||
| has_secrets BOOLEAN, | ||
| PRIMARY KEY ((task_id)) | ||
| ); | ||
|
|
||
| CREATE CUSTOM INDEX IF NOT EXISTS tasks_v2_by_nca_id_sai_idx | ||
| ON nvct_api.tasks_v2 (nca_id) USING 'StorageAttachedIndex'; | ||
|
|
||
| -- Tracks active SIS requests per task. | ||
| CREATE TABLE IF NOT EXISTS nvct_api.sis_requests_by_task ( | ||
| task_id UUID, | ||
| sis_request_id UUID, | ||
| gpu_spec gpu_spec_udt, | ||
| total_request_size INT, | ||
| created_at TIMESTAMP, | ||
| PRIMARY KEY ((task_id), sis_request_id) | ||
| ); | ||
|
|
||
| -- Events emitted during task lifecycle, keyed by task. | ||
| CREATE TABLE IF NOT EXISTS nvct_api.events_by_task ( | ||
| task_id UUID, | ||
| event_id UUID, | ||
| nca_id TEXT, | ||
| message TEXT, | ||
| created_at TIMESTAMP, | ||
| PRIMARY KEY ((task_id), event_id) | ||
| ); | ||
|
|
||
| -- Results produced by a task, keyed by task. | ||
| CREATE TABLE IF NOT EXISTS nvct_api.results_by_task ( | ||
| task_id UUID, | ||
| result_id UUID, | ||
| nca_id TEXT, | ||
| name TEXT, | ||
| metadata TEXT, | ||
| created_at TIMESTAMP, | ||
| PRIMARY KEY ((task_id), result_id) | ||
| ); | ||
|
|
||
| -- Distributed lock table for scheduled background tasks. | ||
| -- Primary key must be 'name'. | ||
| CREATE TABLE IF NOT EXISTS nvct_api.lock ( | ||
| name TEXT, | ||
| lockuntil TIMESTAMP, | ||
| lockedat TIMESTAMP, | ||
| lockedby TEXT, | ||
| PRIMARY KEY ((name)) | ||
| ); | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,6 +16,24 @@ fail() | |||||||||||||||||||||||||||||||
| status=1 | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| schema_inventory=$( | ||||||||||||||||||||||||||||||||
| # shellcheck disable=SC2016 | ||||||||||||||||||||||||||||||||
| sed -n 's/^| `\([^`]*\)`[[:space:]]*| \[[^]]*\].*$/\1/p' \ | ||||||||||||||||||||||||||||||||
| "${keyspaces}/README.md" | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
| for keyspace_name in ${schema_inventory}; do | ||||||||||||||||||||||||||||||||
|
Comment on lines
+19
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Fail closed when the schema inventory is empty. If the README format changes or parsing returns no rows, the loop is skipped and CI reports success without checking any schema. Add an assertion before the loop: Proposed fix schema_inventory=$(
sed -n 's/^| `\([^`]*\)`[[:space:]]*| \[[^]]*\].*$/\1/p' \
"${keyspaces}/README.md"
)
+if [ -z "${schema_inventory}" ]; then
+ fail "schema inventory is empty or malformed"
+fi
for keyspace_name in ${schema_inventory}; do📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| for migration_name in \ | ||||||||||||||||||||||||||||||||
| 01_init_keyspace.up.sql \ | ||||||||||||||||||||||||||||||||
| 02_init_roles.up.sql \ | ||||||||||||||||||||||||||||||||
| 03_init_tables.up.sql | ||||||||||||||||||||||||||||||||
| do | ||||||||||||||||||||||||||||||||
| migration="${keyspaces}/${keyspace_name}/${migration_name}" | ||||||||||||||||||||||||||||||||
| if [ ! -f "${migration}" ]; then | ||||||||||||||||||||||||||||||||
| fail "schema inventory entry ${keyspace_name} is missing ${migration_name}" | ||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if grep -R -n -F 'envOrDefault "REPLICA_COUNT"' "${keyspaces}"; then | ||||||||||||||||||||||||||||||||
| fail "keyspace migrations contain templates unsupported by stock golang-migrate" | ||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: NVIDIA/nvcf
Length of output: 15668
🏁 Script executed:
Repository: NVIDIA/nvcf
Length of output: 12436
🏁 Script executed:
Repository: NVIDIA/nvcf
Length of output: 18466
🌐 Web query:
Apache Cassandra role management GRANT ROLE system_auth.role_members documentation💡 Result:
In Apache Cassandra, the GRANT ROLE statement is used to assign one role to another, establishing a hierarchical relationship where the grantee inherits the permissions of the granted role [1][2]. Role management is handled by the IRoleManager interface, and the default implementation, CassandraRoleManager, persists this information within the system_auth keyspace [3][4][5]. Specifically, the system_auth.role_members table acts as the lookup table that tracks these role-to-role grants [6][5][7]. Key points regarding GRANT ROLE and system_auth.role_members: 1. Syntax: The CQL statement follows the format GRANT role_name TO role_name [1][8]. 2. Functionality: Roles are modeled as a directed acyclic graph (DAG) [1][2]. When a role is granted to another, the grantee acquires all permissions associated with the granted role [1][2]. Circular grants are strictly prohibited by the system [1][8]. 3. Data Storage: The system_auth.role_members table is defined with the following schema: CREATE TABLE system_auth.role_members ( role text, member text, PRIMARY KEY(role, member)); This table stores the mapping of roles to their members (the roles that have been granted to them) [6][5]. While the GRANT ROLE command provides the primary interface for managing these relationships, the system_auth.role_members table is the internal persistent storage mechanism used by the default CassandraRoleManager [4][5]. Direct modification of system tables is generally discouraged in favor of using standard CQL commands [1][9].
Citations:
Use
GRANT ... TO ...for role membership.Replace the
system_auth.role_membersinsert andsystem_auth.roles.member_ofupdate in both migrations with Cassandra’s supported role-grant statement.migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sqlmigrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sqlGRANT <role> TO <role>is the supported CQL path; writingsystem_authdirectly ties the migration to Cassandra internals.📍 Affects 2 files
migrations/cassandra/keyspaces/nvcf_autoscaler/02_init_roles.up.sql#L7-L8(this comment)migrations/cassandra/keyspaces/nvct_api/02_init_roles.up.sql#L7-L8🤖 Prompt for AI Agents
Source: MCP tools