diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 83ea22b628779..9fb52099e9f00 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -881,6 +881,27 @@ func (q *querier) GetAllTailnetClients(ctx context.Context) ([]database.GetAllTa return q.db.GetAllTailnetClients(ctx) } +func (q *querier) GetAllTailnetCoordinators(ctx context.Context) ([]database.TailnetCoordinator, error) { + if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTailnetCoordinator); err != nil { + return nil, err + } + return q.db.GetAllTailnetCoordinators(ctx) +} + +func (q *querier) GetAllTailnetPeers(ctx context.Context) ([]database.TailnetPeer, error) { + if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTailnetCoordinator); err != nil { + return nil, err + } + return q.db.GetAllTailnetPeers(ctx) +} + +func (q *querier) GetAllTailnetTunnels(ctx context.Context) ([]database.TailnetTunnel, error) { + if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTailnetCoordinator); err != nil { + return nil, err + } + return q.db.GetAllTailnetTunnels(ctx) +} + func (q *querier) GetAppSecurityKey(ctx context.Context) (string, error) { // No authz checks return q.db.GetAppSecurityKey(ctx) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index d66b5b225b79a..e076ad68b6c66 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -1276,6 +1276,18 @@ func (*FakeQuerier) GetAllTailnetClients(_ context.Context) ([]database.GetAllTa return nil, ErrUnimplemented } +func (*FakeQuerier) GetAllTailnetCoordinators(context.Context) ([]database.TailnetCoordinator, error) { + return nil, ErrUnimplemented +} + +func (*FakeQuerier) GetAllTailnetPeers(context.Context) ([]database.TailnetPeer, error) { + return nil, ErrUnimplemented +} + +func (*FakeQuerier) GetAllTailnetTunnels(context.Context) ([]database.TailnetTunnel, error) { + return nil, ErrUnimplemented +} + func (q *FakeQuerier) GetAppSecurityKey(_ context.Context) (string, error) { q.mutex.RLock() defer q.mutex.RUnlock() diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 5d8d0f1030088..e37153463a24a 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -314,6 +314,27 @@ func (m metricsStore) GetAllTailnetClients(ctx context.Context) ([]database.GetA return r0, r1 } +func (m metricsStore) GetAllTailnetCoordinators(ctx context.Context) ([]database.TailnetCoordinator, error) { + start := time.Now() + r0, r1 := m.s.GetAllTailnetCoordinators(ctx) + m.queryLatencies.WithLabelValues("GetAllTailnetCoordinators").Observe(time.Since(start).Seconds()) + return r0, r1 +} + +func (m metricsStore) GetAllTailnetPeers(ctx context.Context) ([]database.TailnetPeer, error) { + start := time.Now() + r0, r1 := m.s.GetAllTailnetPeers(ctx) + m.queryLatencies.WithLabelValues("GetAllTailnetPeers").Observe(time.Since(start).Seconds()) + return r0, r1 +} + +func (m metricsStore) GetAllTailnetTunnels(ctx context.Context) ([]database.TailnetTunnel, error) { + start := time.Now() + r0, r1 := m.s.GetAllTailnetTunnels(ctx) + m.queryLatencies.WithLabelValues("GetAllTailnetTunnels").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m metricsStore) GetAppSecurityKey(ctx context.Context) (string, error) { start := time.Now() key, err := m.s.GetAppSecurityKey(ctx) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 2bf37350efbaa..bcc03a77ddd1a 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -532,6 +532,51 @@ func (mr *MockStoreMockRecorder) GetAllTailnetClients(arg0 interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllTailnetClients", reflect.TypeOf((*MockStore)(nil).GetAllTailnetClients), arg0) } +// GetAllTailnetCoordinators mocks base method. +func (m *MockStore) GetAllTailnetCoordinators(arg0 context.Context) ([]database.TailnetCoordinator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllTailnetCoordinators", arg0) + ret0, _ := ret[0].([]database.TailnetCoordinator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllTailnetCoordinators indicates an expected call of GetAllTailnetCoordinators. +func (mr *MockStoreMockRecorder) GetAllTailnetCoordinators(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllTailnetCoordinators", reflect.TypeOf((*MockStore)(nil).GetAllTailnetCoordinators), arg0) +} + +// GetAllTailnetPeers mocks base method. +func (m *MockStore) GetAllTailnetPeers(arg0 context.Context) ([]database.TailnetPeer, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllTailnetPeers", arg0) + ret0, _ := ret[0].([]database.TailnetPeer) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllTailnetPeers indicates an expected call of GetAllTailnetPeers. +func (mr *MockStoreMockRecorder) GetAllTailnetPeers(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllTailnetPeers", reflect.TypeOf((*MockStore)(nil).GetAllTailnetPeers), arg0) +} + +// GetAllTailnetTunnels mocks base method. +func (m *MockStore) GetAllTailnetTunnels(arg0 context.Context) ([]database.TailnetTunnel, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllTailnetTunnels", arg0) + ret0, _ := ret[0].([]database.TailnetTunnel) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllTailnetTunnels indicates an expected call of GetAllTailnetTunnels. +func (mr *MockStoreMockRecorder) GetAllTailnetTunnels(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllTailnetTunnels", reflect.TypeOf((*MockStore)(nil).GetAllTailnetTunnels), arg0) +} + // GetAppSecurityKey mocks base method. func (m *MockStore) GetAppSecurityKey(arg0 context.Context) (string, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 10c6be43a8179..d1b3e070d8b13 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -74,6 +74,10 @@ type sqlcQuerier interface { GetActiveWorkspaceBuildsByTemplateID(ctx context.Context, templateID uuid.UUID) ([]WorkspaceBuild, error) GetAllTailnetAgents(ctx context.Context) ([]TailnetAgent, error) GetAllTailnetClients(ctx context.Context) ([]GetAllTailnetClientsRow, error) + // For PG Coordinator HTMLDebug + GetAllTailnetCoordinators(ctx context.Context) ([]TailnetCoordinator, error) + GetAllTailnetPeers(ctx context.Context) ([]TailnetPeer, error) + GetAllTailnetTunnels(ctx context.Context) ([]TailnetTunnel, error) GetAppSecurityKey(ctx context.Context) (string, error) GetApplicationName(ctx context.Context) (string, error) // GetAuditLogsBefore retrieves `row_limit` number of audit logs before the provided diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 00ca22b0b34db..b5d3f195e7fb4 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -4754,6 +4754,100 @@ func (q *sqlQuerier) GetAllTailnetClients(ctx context.Context) ([]GetAllTailnetC return items, nil } +const getAllTailnetCoordinators = `-- name: GetAllTailnetCoordinators :many + +SELECT id, heartbeat_at FROM tailnet_coordinators +` + +// For PG Coordinator HTMLDebug +func (q *sqlQuerier) GetAllTailnetCoordinators(ctx context.Context) ([]TailnetCoordinator, error) { + rows, err := q.db.QueryContext(ctx, getAllTailnetCoordinators) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TailnetCoordinator + for rows.Next() { + var i TailnetCoordinator + if err := rows.Scan(&i.ID, &i.HeartbeatAt); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllTailnetPeers = `-- name: GetAllTailnetPeers :many +SELECT id, coordinator_id, updated_at, node, status FROM tailnet_peers +` + +func (q *sqlQuerier) GetAllTailnetPeers(ctx context.Context) ([]TailnetPeer, error) { + rows, err := q.db.QueryContext(ctx, getAllTailnetPeers) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TailnetPeer + for rows.Next() { + var i TailnetPeer + if err := rows.Scan( + &i.ID, + &i.CoordinatorID, + &i.UpdatedAt, + &i.Node, + &i.Status, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllTailnetTunnels = `-- name: GetAllTailnetTunnels :many +SELECT coordinator_id, src_id, dst_id, updated_at FROM tailnet_tunnels +` + +func (q *sqlQuerier) GetAllTailnetTunnels(ctx context.Context) ([]TailnetTunnel, error) { + rows, err := q.db.QueryContext(ctx, getAllTailnetTunnels) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TailnetTunnel + for rows.Next() { + var i TailnetTunnel + if err := rows.Scan( + &i.CoordinatorID, + &i.SrcID, + &i.DstID, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getTailnetAgents = `-- name: GetTailnetAgents :many SELECT id, coordinator_id, updated_at, node FROM tailnet_agents diff --git a/coderd/database/queries/tailnet.sql b/coderd/database/queries/tailnet.sql index 011bc6900f2e7..6128c944f9619 100644 --- a/coderd/database/queries/tailnet.sql +++ b/coderd/database/queries/tailnet.sql @@ -199,3 +199,14 @@ SELECT tailnet_tunnels.src_id as peer_id, tailnet_peers.coordinator_id, tailnet_ FROM tailnet_tunnels INNER JOIN tailnet_peers ON tailnet_tunnels.src_id = tailnet_peers.id WHERE tailnet_tunnels.dst_id = $1; + +-- For PG Coordinator HTMLDebug + +-- name: GetAllTailnetCoordinators :many +SELECT * FROM tailnet_coordinators; + +-- name: GetAllTailnetPeers :many +SELECT * FROM tailnet_peers; + +-- name: GetAllTailnetTunnels :many +SELECT * FROM tailnet_tunnels;