-- Agent system migration for Phase 3: Node Agent System -- Create node_agents table CREATE TABLE IF NOT EXISTS node_agents ( id VARCHAR(255) PRIMARY KEY, name VARCHAR(255) NOT NULL, hostname VARCHAR(255) NOT NULL, ip_address VARCHAR(45) NOT NULL, port INTEGER NOT NULL, status VARCHAR(50) DEFAULT 'offline', version VARCHAR(50), capabilities JSONB, resources JSONB, last_heartbeat TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), metadata JSONB ); -- Create container_instances table CREATE TABLE IF NOT EXISTS container_instances ( id VARCHAR(255) PRIMARY KEY, name VARCHAR(255) NOT NULL, image VARCHAR(255) NOT NULL, project_id VARCHAR(255) NOT NULL, service_id VARCHAR(255) NOT NULL, node_agent_id VARCHAR(255) NOT NULL, status JSONB, resources JSONB, ports JSONB, environment JSONB, volumes JSONB, networks JSONB, restart_policy JSONB, health_check JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), started_at TIMESTAMP WITH TIME ZONE, updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), FOREIGN KEY (node_agent_id) REFERENCES node_agents(id) ON DELETE CASCADE ); -- Create agent_commands table CREATE TABLE IF NOT EXISTS agent_commands ( id VARCHAR(255) PRIMARY KEY, type VARCHAR(100) NOT NULL, node_agent_id VARCHAR(255) NOT NULL, container_id VARCHAR(255), payload JSONB, status VARCHAR(50) DEFAULT 'pending', result TEXT, error TEXT, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), completed_at TIMESTAMP WITH TIME ZONE, FOREIGN KEY (node_agent_id) REFERENCES node_agents(id) ON DELETE CASCADE, FOREIGN KEY (container_id) REFERENCES container_instances(id) ON DELETE CASCADE ); -- Create node_clusters table CREATE TABLE IF NOT EXISTS node_clusters ( id VARCHAR(255) PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(50) DEFAULT 'active', total_resources JSONB, used_resources JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Create cluster_agents table to link clusters and agents CREATE TABLE IF NOT EXISTS cluster_agents ( cluster_id VARCHAR(255) NOT NULL, agent_id VARCHAR(255) NOT NULL, added_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), PRIMARY KEY (cluster_id, agent_id), FOREIGN KEY (cluster_id) REFERENCES node_clusters(id) ON DELETE CASCADE, FOREIGN KEY (agent_id) REFERENCES node_agents(id) ON DELETE CASCADE ); -- Create scheduling_rules table CREATE TABLE IF NOT EXISTS scheduling_rules ( id VARCHAR(255) PRIMARY KEY, cluster_id VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(50) NOT NULL, selector JSONB, weight INTEGER DEFAULT 1, enabled BOOLEAN DEFAULT true, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), FOREIGN KEY (cluster_id) REFERENCES node_clusters(id) ON DELETE CASCADE ); -- Create container_metrics table for monitoring CREATE TABLE IF NOT EXISTS container_metrics ( id SERIAL PRIMARY KEY, container_id VARCHAR(255) NOT NULL, timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(), cpu_usage DECIMAL(5,2), cpu_usage_percent DECIMAL(5,2), memory_usage BIGINT, memory_usage_percent DECIMAL(5,2), memory_limit BIGINT, network_rx_bytes BIGINT, network_tx_bytes BIGINT, network_rx_packets BIGINT, network_tx_packets BIGINT, block_read_bytes BIGINT, block_write_bytes BIGINT, pids_current INTEGER, pids_limit INTEGER, FOREIGN KEY (container_id) REFERENCES container_instances(id) ON DELETE CASCADE ); -- Create indexes for performance CREATE INDEX IF NOT EXISTS idx_node_agents_status ON node_agents(status); CREATE INDEX IF NOT EXISTS idx_node_agents_hostname ON node_agents(hostname); CREATE INDEX IF NOT EXISTS idx_node_agents_ip_address ON node_agents(ip_address); CREATE INDEX IF NOT EXISTS idx_node_agents_last_heartbeat ON node_agents(last_heartbeat); CREATE INDEX IF NOT EXISTS idx_container_instances_project_id ON container_instances(project_id); CREATE INDEX IF NOT EXISTS idx_container_instances_service_id ON container_instances(service_id); CREATE INDEX IF NOT EXISTS idx_container_instances_node_agent_id ON container_instances(node_agent_id); CREATE INDEX IF NOT EXISTS idx_container_instances_status ON container_instances USING GIN(status); CREATE INDEX IF NOT EXISTS idx_agent_commands_node_agent_id ON agent_commands(node_agent_id); CREATE INDEX IF NOT EXISTS idx_agent_commands_status ON agent_commands(status); CREATE INDEX IF NOT EXISTS idx_agent_commands_type ON agent_commands(type); CREATE INDEX IF NOT EXISTS idx_agent_commands_created_at ON agent_commands(created_at); CREATE INDEX IF NOT EXISTS idx_container_metrics_container_id ON container_metrics(container_id); CREATE INDEX IF NOT EXISTS idx_container_metrics_timestamp ON container_metrics(timestamp); -- Create updated_at trigger function CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; -- Create triggers for updated_at (only if they don't exist) DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_node_agents_updated_at') THEN CREATE TRIGGER update_node_agents_updated_at BEFORE UPDATE ON node_agents FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_container_instances_updated_at') THEN CREATE TRIGGER update_container_instances_updated_at BEFORE UPDATE ON container_instances FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_agent_commands_updated_at') THEN CREATE TRIGGER update_agent_commands_updated_at BEFORE UPDATE ON agent_commands FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_node_clusters_updated_at') THEN CREATE TRIGGER update_node_clusters_updated_at BEFORE UPDATE ON node_clusters FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_scheduling_rules_updated_at') THEN CREATE TRIGGER update_scheduling_rules_updated_at BEFORE UPDATE ON scheduling_rules FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); END IF; END $$; -- Insert default cluster INSERT INTO node_clusters (id, name, description, status, total_resources, used_resources) VALUES ( 'default-cluster', 'Default Cluster', 'Default cluster for all node agents', 'active', '{"cpu": {"cores": 0, "allocation": 0, "usage": 0}, "memory": {"total": 0, "allocated": 0, "used": 0, "available": 0}, "storage": {"total": 0, "allocated": 0, "used": 0, "available": 0}, "network": {"interfaces": [], "bandwidth": {"inbound": 0, "outbound": 0}}}', '{"cpu": {"cores": 0, "allocation": 0, "usage": 0}, "memory": {"total": 0, "allocated": 0, "used": 0, "available": 0}, "storage": {"total": 0, "allocated": 0, "used": 0, "available": 0}, "network": {"interfaces": [], "bandwidth": {"inbound": 0, "outbound": 0}}}' ) ON CONFLICT (id) DO NOTHING; -- Add comment to tables COMMENT ON TABLE node_agents IS 'Container orchestration agents that manage containers on nodes'; COMMENT ON TABLE container_instances IS 'Container instances running on node agents'; COMMENT ON TABLE agent_commands IS 'Commands sent to node agents for execution'; COMMENT ON TABLE node_clusters IS 'Clusters of node agents for resource pooling'; COMMENT ON TABLE cluster_agents IS 'Many-to-many relationship between clusters and agents'; COMMENT ON TABLE scheduling_rules IS 'Rules for scheduling containers on agents'; COMMENT ON TABLE container_metrics IS 'Metrics collected from running containers';