diff --git a/packaging/mother/mother_schema.sql b/packaging/mother/mother_schema.sql new file mode 100644 index 0000000..7be17ca --- /dev/null +++ b/packaging/mother/mother_schema.sql @@ -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();