Skip to content

feat(provisioner): associate resources with coder_devcontainer#21602

Merged
DanielleMaywood merged 6 commits intomainfrom
danielle/devcontainer-resources/provisioner
Jan 29, 2026
Merged

feat(provisioner): associate resources with coder_devcontainer#21602
DanielleMaywood merged 6 commits intomainfrom
danielle/devcontainer-resources/provisioner

Conversation

@DanielleMaywood
Copy link
Contributor

@DanielleMaywood DanielleMaywood commented Jan 21, 2026

Closes coder/internal#1239

Allow associating coder_env, coder_script and coder_app with coder_devcontainer resource. To do this we make use of the newly added subagent_id field in the coder_devcontainer resource added in coder/terraform-provider-coder#474

@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/provisioner branch 4 times, most recently from 3fb3fe6 to 6d2900e Compare January 21, 2026 11:14
@DanielleMaywood DanielleMaywood force-pushed the danielle/devcontainer-resources/provisioner branch from 6d2900e to 68c3ab5 Compare January 21, 2026 14:48
Comment on lines +1194 to +1216
func dependsOnDevcontainer(graph *gographviz.Graph, dc *proto.Devcontainer, resourceAgentID string, resource *tfjson.StateResource) bool {
// Plan: we need to find if there is an edge between the resource and the devcontainer.
if dc.SubagentId == "" && resourceAgentID == "" {
resourceNodeSuffix := fmt.Sprintf(`] %s.%s (expand)"`, resource.Type, resource.Name)
agentNodeSuffix := fmt.Sprintf(`] coder_devcontainer.%s (expand)"`, dc.Name)

// Traverse the graph to check if the coder_<resource_type> depends on coder_devcontainer.
for _, dst := range graph.Edges.SrcToDsts {
for _, edges := range dst {
for _, edge := range edges {
if strings.HasSuffix(edge.Src, resourceNodeSuffix) &&
strings.HasSuffix(edge.Dst, agentNodeSuffix) {
return true
}
}
}
}
return false
}

// Provision: subagent ID and child resource ID are present
return dc.SubagentId == resourceAgentID
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nit, non-blocking): Could refactor alongside dependsOnAgent given that there are minimal differences between the two functions. Maybe not worth it yet though, so omakase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do the following:

Introduce a new function resourceDependsOn

// resourceDependsOn checks if a resource depends on a target entity (agent or devcontainer).
// During Plan phase (when IDs aren't available), it uses graph edge analysis.
// During Provision phase (when IDs are present), it compares IDs directly.
func resourceDependsOn(graph *gographviz.Graph, resource *tfjson.StateResource, resourceTargetID, targetType, targetName, targetID string) bool {
	// Provision: IDs available, compare directly
	if targetID != "" || resourceTargetID != "" {
		return targetID == resourceTargetID
	}

	// Plan: IDs not yet available, check graph edges
	resourceNodeSuffix := fmt.Sprintf(`] %s.%s (expand)"`, resource.Type, resource.Name)
	targetNodeSuffix := fmt.Sprintf(`] %s.%s (expand)"`, targetType, targetName)

	for _, dst := range graph.Edges.SrcToDsts {
		for _, edges := range dst {
			for _, edge := range edges {
				if strings.HasSuffix(edge.Src, resourceNodeSuffix) &&
					strings.HasSuffix(edge.Dst, targetNodeSuffix) {
					return true
				}
			}
		}
	}
	return false
}

As well as some constants

// Terraform resource type constants for the Coder provider.
const (
	tfCoderAgent         = "coder_agent"
	tfCoderDevcontainer  = "coder_devcontainer"
	...
)

And then the callsites could look like

resourceDependsOn(graph, resource, attrs.AgentID, tfCoderAgent, agent.Name, agent.Id)
resourceDependsOn(graph, resource, attrs.AgentID, tfCoderDevcontainer, dc.Name, dc.SubagentId)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was thinking along those lines. Doesn't necessarily have to be in this PR though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do it in a follow-up PR then

@DanielleMaywood DanielleMaywood marked this pull request as ready for review January 22, 2026 15:33
@github-actions
Copy link

@coder-tasks
Copy link
Contributor

coder-tasks bot commented Jan 22, 2026

Documentation Check

Updates Needed

  • docs/admin/integrations/devcontainers/integration.md - Remove the note stating that coder_script, coder_env, and coder_app cannot be attached to dev container sub-agents (lines 149-162). This PR implements exactly this functionality by allowing these resources to be associated with coder_devcontainer resources via the new subagent_id field.

The note should be updated to reflect that these resources CAN now be attached to dev containers when using the coder_devcontainer resource, and should include example usage showing how to associate them.


Automated review via Coder Tasks

@coder-tasks
Copy link
Contributor

coder-tasks bot commented Jan 28, 2026

Documentation Check

Updates Needed

  • docs/admin/integrations/devcontainers/integration.md - Remove outdated note stating that coder_script, coder_app, and coder_env cannot be attached to devcontainer sub-agents (lines 149-162). Replace with guidance showing how to use the new subagent_id field to associate these resources with devcontainers.

New Documentation Needed

  • docs/admin/integrations/devcontainers/integration.md - Add a new section showing the Terraform pattern for associating apps, scripts, and environment variables with devcontainers using coder_devcontainer.name.subagent_id. Include a code example similar to the test case in provisioner/terraform/testdata/resources/devcontainer-resources/devcontainer-resources.tf.

Example pattern to document:

resource "coder_devcontainer" "dev" {
  agent_id         = coder_agent.main.id
  workspace_folder = "/workspace"
}

resource "coder_app" "devcontainer-app" {
  agent_id = coder_devcontainer.dev.subagent_id
  slug     = "devcontainer-app"
}

resource "coder_script" "devcontainer-script" {
  agent_id     = coder_devcontainer.dev.subagent_id
  display_name = "Devcontainer Script"
  script       = "echo hello"
  run_on_start = true
}

resource "coder_env" "devcontainer-env" {
  agent_id = coder_devcontainer.dev.subagent_id
  name     = "MY_VAR"
  value    = "my-value"
}

Automated review via Coder Tasks

@DanielleMaywood DanielleMaywood merged commit 1a94aa6 into main Jan 29, 2026
29 checks passed
@DanielleMaywood DanielleMaywood deleted the danielle/devcontainer-resources/provisioner branch January 29, 2026 00:01
@github-actions github-actions bot locked and limited conversation to collaborators Jan 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

provisionersdk: Update provisioner protobuf schema for devcontainer resources

3 participants