Skip to content

Commit a473f80

Browse files
committed
fix(coderd): mark sub agent deletion via boolean instead of delete
Fixes coder/internal#685
1 parent b9ac16c commit a473f80

File tree

10 files changed

+182
-28
lines changed

10 files changed

+182
-28
lines changed

coderd/agentapi/api.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,13 +196,14 @@ func New(opts Options) *API {
196196
}
197197

198198
api.SubAgentAPI = &SubAgentAPI{
199-
OwnerID: opts.OwnerID,
200-
OrganizationID: opts.OrganizationID,
201-
AgentID: opts.AgentID,
202-
AgentFn: api.agent,
203-
Log: opts.Log,
204-
Clock: opts.Clock,
205-
Database: opts.Database,
199+
OwnerID: opts.OwnerID,
200+
OrganizationID: opts.OrganizationID,
201+
AgentID: opts.AgentID,
202+
AgentFn: api.agent,
203+
PublishWorkspaceUpdateFn: api.publishWorkspaceUpdate,
204+
Log: opts.Log,
205+
Clock: opts.Clock,
206+
Database: opts.Database,
206207
}
207208

208209
return api

coderd/database/dump.sql

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
ALTER TABLE workspace_agents
2+
DROP COLUMN deleted;
3+
4+
-- Restore trigger without deleted check.
5+
DROP TRIGGER IF EXISTS workspace_agent_name_unique_trigger ON workspace_agents;
6+
DROP FUNCTION IF EXISTS check_workspace_agent_name_unique();
7+
8+
CREATE OR REPLACE FUNCTION check_workspace_agent_name_unique()
9+
RETURNS TRIGGER AS $$
10+
DECLARE
11+
workspace_build_id uuid;
12+
agents_with_name int;
13+
BEGIN
14+
-- Find the workspace build the workspace agent is being inserted into.
15+
SELECT workspace_builds.id INTO workspace_build_id
16+
FROM workspace_resources
17+
JOIN workspace_builds ON workspace_builds.job_id = workspace_resources.job_id
18+
WHERE workspace_resources.id = NEW.resource_id;
19+
20+
-- If the agent doesn't have a workspace build, we'll allow the insert.
21+
IF workspace_build_id IS NULL THEN
22+
RETURN NEW;
23+
END IF;
24+
25+
-- Count how many agents in this workspace build already have the given agent name.
26+
SELECT COUNT(*) INTO agents_with_name
27+
FROM workspace_agents
28+
JOIN workspace_resources ON workspace_resources.id = workspace_agents.resource_id
29+
JOIN workspace_builds ON workspace_builds.job_id = workspace_resources.job_id
30+
WHERE workspace_builds.id = workspace_build_id
31+
AND workspace_agents.name = NEW.name
32+
AND workspace_agents.id != NEW.id;
33+
34+
-- If there's already an agent with this name, raise an error
35+
IF agents_with_name > 0 THEN
36+
RAISE EXCEPTION 'workspace agent name "%" already exists in this workspace build', NEW.name
37+
USING ERRCODE = 'unique_violation';
38+
END IF;
39+
40+
RETURN NEW;
41+
END;
42+
$$ LANGUAGE plpgsql;
43+
44+
CREATE TRIGGER workspace_agent_name_unique_trigger
45+
BEFORE INSERT OR UPDATE OF name, resource_id ON workspace_agents
46+
FOR EACH ROW
47+
EXECUTE FUNCTION check_workspace_agent_name_unique();
48+
49+
COMMENT ON TRIGGER workspace_agent_name_unique_trigger ON workspace_agents IS
50+
'Use a trigger instead of a unique constraint because existing data may violate
51+
the uniqueness requirement. A trigger allows us to enforce uniqueness going
52+
forward without requiring a migration to clean up historical data.';
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
ALTER TABLE workspace_agents
2+
ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE;
3+
4+
COMMENT ON COLUMN workspace_agents.deleted IS 'Indicates whether or not the agent has been deleted. This is currently only applicable to sub agents.';
5+
6+
-- Recreate the trigger with deleted check.
7+
DROP TRIGGER IF EXISTS workspace_agent_name_unique_trigger ON workspace_agents;
8+
DROP FUNCTION IF EXISTS check_workspace_agent_name_unique();
9+
10+
CREATE OR REPLACE FUNCTION check_workspace_agent_name_unique()
11+
RETURNS TRIGGER AS $$
12+
DECLARE
13+
workspace_build_id uuid;
14+
agents_with_name int;
15+
BEGIN
16+
-- Find the workspace build the workspace agent is being inserted into.
17+
SELECT workspace_builds.id INTO workspace_build_id
18+
FROM workspace_resources
19+
JOIN workspace_builds ON workspace_builds.job_id = workspace_resources.job_id
20+
WHERE workspace_resources.id = NEW.resource_id;
21+
22+
-- If the agent doesn't have a workspace build, we'll allow the insert.
23+
IF workspace_build_id IS NULL THEN
24+
RETURN NEW;
25+
END IF;
26+
27+
-- Count how many agents in this workspace build already have the given agent name.
28+
SELECT COUNT(*) INTO agents_with_name
29+
FROM workspace_agents
30+
JOIN workspace_resources ON workspace_resources.id = workspace_agents.resource_id
31+
JOIN workspace_builds ON workspace_builds.job_id = workspace_resources.job_id
32+
WHERE workspace_builds.id = workspace_build_id
33+
AND workspace_agents.name = NEW.name
34+
AND workspace_agents.id != NEW.id
35+
AND workspace_agents.deleted = FALSE; -- Ensure we only count non-deleted agents.
36+
37+
-- If there's already an agent with this name, raise an error
38+
IF agents_with_name > 0 THEN
39+
RAISE EXCEPTION 'workspace agent name "%" already exists in this workspace build', NEW.name
40+
USING ERRCODE = 'unique_violation';
41+
END IF;
42+
43+
RETURN NEW;
44+
END;
45+
$$ LANGUAGE plpgsql;
46+
47+
CREATE TRIGGER workspace_agent_name_unique_trigger
48+
BEFORE INSERT OR UPDATE OF name, resource_id ON workspace_agents
49+
FOR EACH ROW
50+
EXECUTE FUNCTION check_workspace_agent_name_unique();
51+
52+
COMMENT ON TRIGGER workspace_agent_name_unique_trigger ON workspace_agents IS
53+
'Use a trigger instead of a unique constraint because existing data may violate
54+
the uniqueness requirement. A trigger allows us to enforce uniqueness going
55+
forward without requiring a migration to clean up historical data.';

coderd/database/models.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)