refactor: add postgres tailnet coordinator (#8044)

* postgres tailnet coordinator

Signed-off-by: Spike Curtis <spike@coder.com>

* Fix db migration; tests

Signed-off-by: Spike Curtis <spike@coder.com>

* Add fixture, regenerate

Signed-off-by: Spike Curtis <spike@coder.com>

* Fix fixtures

Signed-off-by: Spike Curtis <spike@coder.com>

* review comments, run clean gen

Signed-off-by: Spike Curtis <spike@coder.com>

* Rename waitForConn -> cleanupConn

Signed-off-by: Spike Curtis <spike@coder.com>

* code review updates

Signed-off-by: Spike Curtis <spike@coder.com>

* db migration order

Signed-off-by: Spike Curtis <spike@coder.com>

* fix log field name last_heartbeat

Signed-off-by: Spike Curtis <spike@coder.com>

* fix heartbeat_from log field

Signed-off-by: Spike Curtis <spike@coder.com>

* fix slog fields for linting

Signed-off-by: Spike Curtis <spike@coder.com>

---------

Signed-off-by: Spike Curtis <spike@coder.com>
This commit is contained in:
Spike Curtis
2023-06-21 16:20:58 +04:00
committed by GitHub
parent 4fb4c9b270
commit cc17d2feea
20 changed files with 2739 additions and 18 deletions

View File

@ -0,0 +1,18 @@
BEGIN;
DROP TRIGGER IF EXISTS tailnet_notify_client_change ON tailnet_clients;
DROP FUNCTION IF EXISTS tailnet_notify_client_change;
DROP INDEX IF EXISTS idx_tailnet_clients_agent;
DROP INDEX IF EXISTS idx_tailnet_clients_coordinator;
DROP TABLE tailnet_clients;
DROP TRIGGER IF EXISTS tailnet_notify_agent_change ON tailnet_agents;
DROP FUNCTION IF EXISTS tailnet_notify_agent_change;
DROP INDEX IF EXISTS idx_tailnet_agents_coordinator;
DROP TABLE IF EXISTS tailnet_agents;
DROP TRIGGER IF EXISTS tailnet_notify_coordinator_heartbeat ON tailnet_coordinators;
DROP FUNCTION IF EXISTS tailnet_notify_coordinator_heartbeat;
DROP TABLE IF EXISTS tailnet_coordinators;
COMMIT;

View File

@ -0,0 +1,97 @@
BEGIN;
CREATE TABLE tailnet_coordinators (
id uuid NOT NULL PRIMARY KEY,
heartbeat_at timestamp with time zone NOT NULL
);
COMMENT ON TABLE tailnet_coordinators IS 'We keep this separate from replicas in case we need to break the coordinator out into its own service';
CREATE TABLE tailnet_clients (
id uuid NOT NULL,
coordinator_id uuid NOT NULL,
agent_id uuid NOT NULL,
updated_at timestamp with time zone NOT NULL,
node jsonb NOT NULL,
PRIMARY KEY (id, coordinator_id),
FOREIGN KEY (coordinator_id) REFERENCES tailnet_coordinators(id) ON DELETE CASCADE
);
-- For querying/deleting mappings
CREATE INDEX idx_tailnet_clients_agent ON tailnet_clients (agent_id);
-- For shutting down / GC a coordinator
CREATE INDEX idx_tailnet_clients_coordinator ON tailnet_clients (coordinator_id);
CREATE TABLE tailnet_agents (
id uuid NOT NULL,
coordinator_id uuid NOT NULL,
updated_at timestamp with time zone NOT NULL,
node jsonb NOT NULL,
PRIMARY KEY (id, coordinator_id),
FOREIGN KEY (coordinator_id) REFERENCES tailnet_coordinators(id) ON DELETE CASCADE
);
-- For shutting down / GC a coordinator
CREATE INDEX idx_tailnet_agents_coordinator ON tailnet_agents (coordinator_id);
-- Any time the tailnet_clients table changes, send an update with the affected client and agent IDs
CREATE FUNCTION tailnet_notify_client_change() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF (OLD IS NOT NULL) THEN
PERFORM pg_notify('tailnet_client_update', OLD.id || ',' || OLD.agent_id);
RETURN NULL;
END IF;
IF (NEW IS NOT NULL) THEN
PERFORM pg_notify('tailnet_client_update', NEW.id || ',' || NEW.agent_id);
RETURN NULL;
END IF;
END;
$$;
CREATE TRIGGER tailnet_notify_client_change
AFTER INSERT OR UPDATE OR DELETE ON tailnet_clients
FOR EACH ROW
EXECUTE PROCEDURE tailnet_notify_client_change();
-- Any time tailnet_agents table changes, send an update with the affected agent ID.
CREATE FUNCTION tailnet_notify_agent_change() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF (OLD IS NOT NULL) THEN
PERFORM pg_notify('tailnet_agent_update', OLD.id::text);
RETURN NULL;
END IF;
IF (NEW IS NOT NULL) THEN
PERFORM pg_notify('tailnet_agent_update', NEW.id::text);
RETURN NULL;
END IF;
END;
$$;
CREATE TRIGGER tailnet_notify_agent_change
AFTER INSERT OR UPDATE OR DELETE ON tailnet_agents
FOR EACH ROW
EXECUTE PROCEDURE tailnet_notify_agent_change();
-- Send coordinator heartbeats
CREATE FUNCTION tailnet_notify_coordinator_heartbeat() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
PERFORM pg_notify('tailnet_coordinator_heartbeat', NEW.id::text);
RETURN NULL;
END;
$$;
CREATE TRIGGER tailnet_notify_coordinator_heartbeat
AFTER INSERT OR UPDATE ON tailnet_coordinators
FOR EACH ROW
EXECUTE PROCEDURE tailnet_notify_coordinator_heartbeat();
COMMIT;

View File

@ -0,0 +1,28 @@
INSERT INTO tailnet_coordinators
(id, heartbeat_at)
VALUES
(
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'2023-06-15 10:23:54+00'
);
INSERT INTO tailnet_clients
(id, agent_id, coordinator_id, updated_at, node)
VALUES
(
'b0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'c0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'2023-06-15 10:23:54+00',
'{"preferred_derp": 12}'::json
);
INSERT INTO tailnet_agents
(id, coordinator_id, updated_at, node)
VALUES
(
'c0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'2023-06-15 10:23:54+00',
'{"preferred_derp": 13}'::json
);