feat: PostgreSQL schema for mother node — node registry + build queue #152
1 changed files with 85 additions and 0 deletions
85
packaging/mother/mother_schema.sql
Normal file
85
packaging/mother/mother_schema.sql
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
CREATE TABLE IF NOT EXISTS usb_nodes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
hostname TEXT NOT NULL UNIQUE,
|
||||
last_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
first_seen TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
freebsd_version JSONB,
|
||||
hw_profile JSONB NOT NULL,
|
||||
capabilities JSONB,
|
||||
status TEXT NOT NULL DEFAULT 'offline',
|
||||
tags TEXT[] DEFAULT '{}',
|
||||
last_cap_sync TIMESTAMPTZ
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_status ON usb_nodes (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_last_seen ON usb_nodes (last_seen DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_cap_has_gpu ON usb_nodes ((capabilities->>'has_gpu'));
|
||||
CREATE TABLE IF NOT EXISTS build_queue (
|
||||
id SERIAL PRIMARY KEY,
|
||||
node_id INTEGER REFERENCES usb_nodes(id),
|
||||
crate TEXT NOT NULL DEFAULT 'colibri-daemon',
|
||||
branch TEXT NOT NULL DEFAULT 'main',
|
||||
release BOOLEAN NOT NULL DEFAULT true,
|
||||
status TEXT NOT NULL DEFAULT 'queued',
|
||||
priority INTEGER NOT NULL DEFAULT 0,
|
||||
queued_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
started_at TIMESTAMPTZ,
|
||||
completed_at TIMESTAMPTZ,
|
||||
binary_path TEXT,
|
||||
binary_size BIGINT,
|
||||
commit_sha TEXT,
|
||||
duration_s INTEGER,
|
||||
error_log TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_build_status ON build_queue (status, priority DESC, queued_at);
|
||||
CREATE TABLE IF NOT EXISTS audit_log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
event_ts TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
event_type TEXT NOT NULL,
|
||||
node_id INTEGER REFERENCES usb_nodes(id),
|
||||
build_id INTEGER REFERENCES build_queue(id),
|
||||
details JSONB
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_ts ON audit_log (event_ts DESC);
|
||||
|
||||
CREATE OR REPLACE FUNCTION derive_capabilities()
|
||||
RETURNS trigger AS $$
|
||||
DECLARE
|
||||
ram INTEGER;
|
||||
drivers TEXT;
|
||||
wifi JSONB;
|
||||
caps JSONB := '{}'::JSONB;
|
||||
BEGIN
|
||||
ram := COALESCE((NEW.hw_profile->>'ram_gb')::INTEGER, 0);
|
||||
drivers := NEW.hw_profile->>'gpu_driver';
|
||||
wifi := NEW.hw_profile->'wifi';
|
||||
IF NEW.hw_profile->'gpu' IS NOT NULL AND jsonb_array_length(NEW.hw_profile->'gpu') > 0 THEN
|
||||
caps := caps || '{"has_gpu": true}'::JSONB;
|
||||
IF drivers ILIKE '%amdgpu%' THEN
|
||||
caps := caps || '{"gpu_vendor": "amd", "vulkan_compute": true}'::JSONB;
|
||||
ELSIF drivers ILIKE '%nvidia%' THEN
|
||||
caps := caps || '{"gpu_vendor": "nvidia"}'::JSONB;
|
||||
END IF;
|
||||
ELSE
|
||||
caps := caps || '{"has_gpu": false, "cpu_only": true}'::JSONB;
|
||||
END IF;
|
||||
IF caps->>'has_gpu' = 'true' AND caps->>'gpu_vendor' = 'nvidia' THEN
|
||||
caps := caps || '{"can_run_local_llm": true}'::JSONB;
|
||||
IF ram >= 64 THEN caps := caps || '{"max_model": "13b-q4"}'::JSONB;
|
||||
ELSIF ram >= 32 THEN caps := caps || '{"max_model": "7b-q4"}'::JSONB;
|
||||
END IF;
|
||||
ELSIF ram >= 16 THEN
|
||||
caps := caps || '{"can_run_local_llm": true, "max_model": "3b"}'::JSONB;
|
||||
END IF;
|
||||
IF wifi IS NOT NULL AND jsonb_array_length(wifi) > 0 THEN
|
||||
caps := caps || '{"has_wifi": true}'::JSONB;
|
||||
END IF;
|
||||
NEW.capabilities := caps;
|
||||
NEW.last_cap_sync := now();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_derive_capabilities ON usb_nodes;
|
||||
CREATE TRIGGER trg_derive_capabilities
|
||||
BEFORE INSERT OR UPDATE OF hw_profile ON usb_nodes
|
||||
FOR EACH ROW EXECUTE FUNCTION derive_capabilities();
|
||||
Loading…
Add table
Reference in a new issue