forked from wrenn/wrenn
Disk sizing: - Add disk_size_mb column to sandboxes table (default 20480 = 20GB) - Add disk_size_mb to CreateSandboxRequest proto, passed through the full chain: service → RPC → host agent → sandbox manager → devicemapper - devicemapper.CreateSnapshot takes separate cowSizeBytes param so the sparse CoW file can be sized independently from the origin - EnsureImageSizes() runs at host agent startup: expands any base image smaller than 20GB via truncate + resize2fs (sparse, no extra physical disk). Sandboxes then get the full 20GB via fast dm-snapshot path - FlattenRootfs shrinks output images with resize2fs -M so stored templates are compact; EnsureImageSizes re-expands on next startup Admin templates visibility: - Add GET /v1/admin/templates endpoint listing all templates across teams - Frontend admin templates page uses listAdminTemplates() instead of team-scoped listSnapshots() - Platform templates (team_id = all-zeros UUID) now visible to all teams: GetTemplateByTeam, ListTemplatesByTeam, ListTemplatesByTeamAndType queries include platform team_id in WHERE clause
238 lines
8.4 KiB
SQL
238 lines
8.4 KiB
SQL
-- +goose Up
|
|
|
|
-- teams
|
|
CREATE TABLE teams (
|
|
id UUID PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
is_byoc BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX idx_teams_slug ON teams(slug);
|
|
|
|
-- users
|
|
CREATE TABLE users (
|
|
id UUID PRIMARY KEY,
|
|
email TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT,
|
|
name TEXT NOT NULL DEFAULT '',
|
|
is_admin BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- users_teams (junction)
|
|
CREATE TABLE users_teams (
|
|
user_id UUID NOT NULL REFERENCES users(id),
|
|
team_id UUID NOT NULL REFERENCES teams(id),
|
|
is_default BOOLEAN NOT NULL DEFAULT FALSE,
|
|
role TEXT NOT NULL DEFAULT 'member',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (team_id, user_id)
|
|
);
|
|
CREATE INDEX idx_users_teams_user ON users_teams(user_id);
|
|
|
|
-- team_api_keys
|
|
CREATE TABLE team_api_keys (
|
|
id UUID PRIMARY KEY,
|
|
team_id UUID NOT NULL REFERENCES teams(id),
|
|
name TEXT NOT NULL,
|
|
key_hash TEXT NOT NULL UNIQUE,
|
|
key_prefix TEXT NOT NULL,
|
|
created_by UUID NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
last_used TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX idx_team_api_keys_team ON team_api_keys(team_id);
|
|
|
|
-- oauth_providers
|
|
CREATE TABLE oauth_providers (
|
|
provider TEXT NOT NULL,
|
|
provider_id TEXT NOT NULL,
|
|
user_id UUID NOT NULL REFERENCES users(id),
|
|
email TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
PRIMARY KEY (provider, provider_id)
|
|
);
|
|
CREATE INDEX idx_oauth_providers_user ON oauth_providers(user_id);
|
|
|
|
-- admin_permissions
|
|
CREATE TABLE admin_permissions (
|
|
id UUID PRIMARY KEY,
|
|
user_id UUID NOT NULL REFERENCES users(id),
|
|
permission TEXT NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
UNIQUE (user_id, permission)
|
|
);
|
|
CREATE INDEX idx_admin_permissions_user ON admin_permissions(user_id);
|
|
|
|
-- hosts
|
|
CREATE TABLE hosts (
|
|
id UUID PRIMARY KEY,
|
|
type TEXT NOT NULL DEFAULT 'regular',
|
|
team_id UUID REFERENCES teams(id),
|
|
provider TEXT NOT NULL DEFAULT '',
|
|
availability_zone TEXT NOT NULL DEFAULT '',
|
|
arch TEXT NOT NULL DEFAULT '',
|
|
cpu_cores INTEGER NOT NULL DEFAULT 0,
|
|
memory_mb INTEGER NOT NULL DEFAULT 0,
|
|
disk_gb INTEGER NOT NULL DEFAULT 0,
|
|
address TEXT NOT NULL DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
last_heartbeat_at TIMESTAMPTZ,
|
|
metadata JSONB NOT NULL DEFAULT '{}',
|
|
created_by UUID NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
cert_fingerprint TEXT NOT NULL DEFAULT '',
|
|
mtls_enabled BOOLEAN NOT NULL DEFAULT FALSE
|
|
);
|
|
CREATE INDEX idx_hosts_type ON hosts(type);
|
|
CREATE INDEX idx_hosts_team ON hosts(team_id);
|
|
CREATE INDEX idx_hosts_status ON hosts(status);
|
|
|
|
-- host_tokens
|
|
CREATE TABLE host_tokens (
|
|
id UUID PRIMARY KEY,
|
|
host_id UUID NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,
|
|
created_by UUID NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
used_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX idx_host_tokens_host ON host_tokens(host_id);
|
|
|
|
-- host_tags
|
|
CREATE TABLE host_tags (
|
|
host_id UUID NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,
|
|
tag TEXT NOT NULL,
|
|
PRIMARY KEY (host_id, tag)
|
|
);
|
|
CREATE INDEX idx_host_tags_tag ON host_tags(tag);
|
|
|
|
-- host_refresh_tokens
|
|
CREATE TABLE host_refresh_tokens (
|
|
id UUID PRIMARY KEY,
|
|
host_id UUID NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
revoked_at TIMESTAMPTZ
|
|
);
|
|
CREATE INDEX idx_host_refresh_tokens_host ON host_refresh_tokens(host_id);
|
|
|
|
-- templates (TEXT primary key — not UUID)
|
|
CREATE TABLE templates (
|
|
name TEXT PRIMARY KEY,
|
|
type TEXT NOT NULL DEFAULT 'base',
|
|
vcpus INTEGER NOT NULL DEFAULT 1,
|
|
memory_mb INTEGER NOT NULL DEFAULT 512,
|
|
size_bytes BIGINT NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
team_id UUID NOT NULL
|
|
);
|
|
CREATE INDEX idx_templates_team ON templates(team_id);
|
|
|
|
-- sandboxes
|
|
CREATE TABLE sandboxes (
|
|
id UUID PRIMARY KEY,
|
|
team_id UUID NOT NULL REFERENCES teams(id),
|
|
host_id UUID NOT NULL,
|
|
template TEXT NOT NULL DEFAULT 'minimal',
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
vcpus INTEGER NOT NULL DEFAULT 1,
|
|
memory_mb INTEGER NOT NULL DEFAULT 512,
|
|
timeout_sec INTEGER NOT NULL DEFAULT 300,
|
|
disk_size_mb INTEGER NOT NULL DEFAULT 20480,
|
|
guest_ip TEXT NOT NULL DEFAULT '',
|
|
host_ip TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
started_at TIMESTAMPTZ,
|
|
last_active_at TIMESTAMPTZ,
|
|
last_updated TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX idx_sandboxes_status ON sandboxes(status);
|
|
CREATE INDEX idx_sandboxes_host_status ON sandboxes(host_id, status);
|
|
CREATE INDEX idx_sandboxes_team ON sandboxes(team_id);
|
|
|
|
-- audit_logs (id and team_id are UUID; actor_id and resource_id are TEXT for polymorphism)
|
|
CREATE TABLE audit_logs (
|
|
id UUID PRIMARY KEY,
|
|
team_id UUID NOT NULL,
|
|
actor_type TEXT NOT NULL,
|
|
actor_id TEXT,
|
|
actor_name TEXT NOT NULL DEFAULT '',
|
|
resource_type TEXT NOT NULL,
|
|
resource_id TEXT,
|
|
action TEXT NOT NULL,
|
|
scope TEXT NOT NULL DEFAULT 'team',
|
|
status TEXT NOT NULL DEFAULT 'success',
|
|
metadata JSONB NOT NULL DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
CREATE INDEX idx_audit_logs_team_time ON audit_logs(team_id, created_at DESC);
|
|
CREATE INDEX idx_audit_logs_team_resource ON audit_logs(team_id, resource_type, created_at DESC);
|
|
|
|
-- sandbox_metrics_snapshots
|
|
CREATE TABLE sandbox_metrics_snapshots (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
team_id UUID NOT NULL,
|
|
sampled_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
running_count INTEGER NOT NULL DEFAULT 0,
|
|
vcpus_reserved INTEGER NOT NULL DEFAULT 0,
|
|
memory_mb_reserved INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
CREATE INDEX idx_metrics_snapshots_team_time ON sandbox_metrics_snapshots(team_id, sampled_at DESC);
|
|
|
|
-- sandbox_metric_points
|
|
CREATE TABLE sandbox_metric_points (
|
|
sandbox_id UUID NOT NULL,
|
|
tier TEXT NOT NULL CHECK (tier IN ('10m', '2h', '24h')),
|
|
ts BIGINT NOT NULL,
|
|
cpu_pct FLOAT8 NOT NULL DEFAULT 0,
|
|
mem_bytes BIGINT NOT NULL DEFAULT 0,
|
|
disk_bytes BIGINT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (sandbox_id, tier, ts)
|
|
);
|
|
CREATE INDEX idx_sandbox_metric_points_sandbox_tier ON sandbox_metric_points(sandbox_id, tier);
|
|
|
|
-- template_builds
|
|
CREATE TABLE template_builds (
|
|
id UUID PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
base_template TEXT NOT NULL,
|
|
recipe JSONB NOT NULL DEFAULT '[]',
|
|
healthcheck TEXT NOT NULL DEFAULT '',
|
|
vcpus INTEGER NOT NULL DEFAULT 1,
|
|
memory_mb INTEGER NOT NULL DEFAULT 512,
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
current_step INTEGER NOT NULL DEFAULT 0,
|
|
total_steps INTEGER NOT NULL DEFAULT 0,
|
|
logs JSONB NOT NULL DEFAULT '[]',
|
|
error TEXT NOT NULL DEFAULT '',
|
|
sandbox_id UUID,
|
|
host_id UUID,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
started_at TIMESTAMPTZ,
|
|
completed_at TIMESTAMPTZ
|
|
);
|
|
|
|
-- +goose Down
|
|
DROP TABLE IF EXISTS template_builds;
|
|
DROP TABLE IF EXISTS sandbox_metric_points;
|
|
DROP TABLE IF EXISTS sandbox_metrics_snapshots;
|
|
DROP TABLE IF EXISTS audit_logs;
|
|
DROP TABLE IF EXISTS sandboxes;
|
|
DROP TABLE IF EXISTS templates;
|
|
DROP TABLE IF EXISTS host_refresh_tokens;
|
|
DROP TABLE IF EXISTS host_tags;
|
|
DROP TABLE IF EXISTS host_tokens;
|
|
DROP TABLE IF EXISTS hosts;
|
|
DROP TABLE IF EXISTS admin_permissions;
|
|
DROP TABLE IF EXISTS oauth_providers;
|
|
DROP TABLE IF EXISTS team_api_keys;
|
|
DROP TABLE IF EXISTS users_teams;
|
|
DROP TABLE IF EXISTS users;
|
|
DROP TABLE IF EXISTS teams;
|