fix(master): refuse jobs for revoked agents, signal revoked jobs, agent start time wins (#7)

This commit is contained in:
2026-10-12 19:14:32 +02:00
parent 93ba6915b9
commit c09e774d74
6 changed files with 138 additions and 57 deletions
+18 -12
View File
@@ -63,33 +63,39 @@ func (s *Store) AgentByTokenHash(ctx context.Context, hash string) (model.Agent,
return scanAgent(s.pool.QueryRow(ctx, `SELECT `+agentColumns+` FROM agents WHERE token_hash = $1`, hash))
}
// RevokeAgent marks the agent revoked and its Compose and plain-container
// services removed and its queued and running jobs failed, in one transaction. Swarm rows are shared with other
// managers and left alone. Its token stops working immediately; closing a
// live connection is the hub's job.
func (s *Store) RevokeAgent(ctx context.Context, id int64, at time.Time) error {
// RevokeAgent marks the agent revoked, its Compose and plain-container
// services removed and its queued and running jobs failed, in one
// transaction, and returns the IDs of the jobs it failed. Swarm rows are
// shared with other managers and left alone. Its token stops working
// immediately; closing a live connection is the hub's job.
func (s *Store) RevokeAgent(ctx context.Context, id int64, at time.Time) ([]int64, error) {
tx, err := s.pool.Begin(ctx)
if err != nil {
return fmt.Errorf("revoke agent: begin: %w", err)
return nil, fmt.Errorf("revoke agent: begin: %w", err)
}
defer func() { _ = tx.Rollback(ctx) }()
if _, err := tx.Exec(ctx,
`UPDATE agents SET revoked_at = $2 WHERE id = $1 AND revoked_at IS NULL`, id, at); err != nil {
return fmt.Errorf("revoke agent: %w", err)
return nil, fmt.Errorf("revoke agent: %w", err)
}
if _, err := tx.Exec(ctx,
`UPDATE services SET removed_at = $2
WHERE agent_id = $1 AND kind IN ('compose', 'container') AND removed_at IS NULL`, id, at); err != nil {
return fmt.Errorf("revoke agent: remove services: %w", err)
return nil, fmt.Errorf("revoke agent: remove services: %w", err)
}
if _, err := tx.Exec(ctx, failActiveJobsSQL, id, "agent revoked", at); err != nil {
return fmt.Errorf("revoke agent: fail jobs: %w", err)
rows, err := tx.Query(ctx, failActiveJobsSQL, id, "agent revoked", at)
if err != nil {
return nil, fmt.Errorf("revoke agent: fail jobs: %w", err)
}
failed, err := pgx.CollectRows(rows, pgx.RowTo[int64])
if err != nil {
return nil, fmt.Errorf("revoke agent: fail jobs: %w", err)
}
if err := tx.Commit(ctx); err != nil {
return fmt.Errorf("revoke agent: commit: %w", err)
return nil, fmt.Errorf("revoke agent: commit: %w", err)
}
return nil
return failed, nil
}
// RecordHello stores what the agent reported about itself on connect.