From eed76e28cedcf85ef71bf16c277d54c8b84f04fd Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Wed, 19 Mar 2025 11:56:40 +0000 Subject: [PATCH 1/2] feat: add `coder_devcontainer` resource This change will allow autostarting Dev Containers. This is implemented as a resource instead of a `schema.TypeSet` on the agent resource to allow definition via Coder modules. Updates coder/coder#16423 --- docs/resources/devcontainer.md | 29 ++++++++++ provider/devcontainer.go | 46 ++++++++++++++++ provider/devcontainer_test.go | 98 ++++++++++++++++++++++++++++++++++ provider/provider.go | 1 + 4 files changed, 174 insertions(+) create mode 100644 docs/resources/devcontainer.md create mode 100644 provider/devcontainer.go create mode 100644 provider/devcontainer_test.go diff --git a/docs/resources/devcontainer.md b/docs/resources/devcontainer.md new file mode 100644 index 0000000..896786d --- /dev/null +++ b/docs/resources/devcontainer.md @@ -0,0 +1,29 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "coder_devcontainer Resource - terraform-provider-coder" +subcategory: "" +description: |- + Define a Dev Container the agent should know of and attempt to autostart. +--- + +# coder_devcontainer (Resource) + +Define a Dev Container the agent should know of and attempt to autostart. + + + + +## Schema + +### Required + +- `agent_id` (String) The `id` property of a `coder_agent` resource to associate with. +- `workspace_folder` (String) The workspace folder to for the Dev Container. + +### Optional + +- `config_path` (String) The path to the Dev Container configuration file (devcontainer.json). + +### Read-Only + +- `id` (String) The ID of this resource. diff --git a/provider/devcontainer.go b/provider/devcontainer.go new file mode 100644 index 0000000..bfe99f0 --- /dev/null +++ b/provider/devcontainer.go @@ -0,0 +1,46 @@ +package provider + +import ( + "context" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func devcontainerResource() *schema.Resource { + return &schema.Resource{ + SchemaVersion: 1, + + Description: "Define a Dev Container the agent should know of and attempt to autostart.", + CreateContext: func(_ context.Context, rd *schema.ResourceData, _ interface{}) diag.Diagnostics { + rd.SetId(uuid.NewString()) + + return nil + }, + ReadContext: schema.NoopContext, + DeleteContext: schema.NoopContext, + Schema: map[string]*schema.Schema{ + "agent_id": { + Type: schema.TypeString, + Description: "The `id` property of a `coder_agent` resource to associate with.", + ForceNew: true, + Required: true, + }, + "workspace_folder": { + Type: schema.TypeString, + Description: "The workspace folder to for the Dev Container.", + ForceNew: true, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "config_path": { + Type: schema.TypeString, + Description: "The path to the Dev Container configuration file (devcontainer.json).", + ForceNew: true, + Optional: true, + }, + }, + } +} diff --git a/provider/devcontainer_test.go b/provider/devcontainer_test.go new file mode 100644 index 0000000..784cfb0 --- /dev/null +++ b/provider/devcontainer_test.go @@ -0,0 +1,98 @@ +package provider_test + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestDevcontainer(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + } + resource "coder_devcontainer" "example" { + agent_id = "king" + workspace_folder = "/workspace" + config_path = "/workspace/devcontainer.json" + } + `, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + script := state.Modules[0].Resources["coder_devcontainer.example"] + require.NotNil(t, script) + t.Logf("script attributes: %#v", script.Primary.Attributes) + for key, expected := range map[string]string{ + "agent_id": "king", + "workspace_folder": "/workspace", + "config_path": "/workspace/devcontainer.json", + } { + require.Equal(t, expected, script.Primary.Attributes[key]) + } + return nil + }, + }}, + }) +} + +func TestDevcontainerNoConfigPath(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + } + resource "coder_devcontainer" "example" { + agent_id = "king" + workspace_folder = "/workspace" + } + `, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + script := state.Modules[0].Resources["coder_devcontainer.example"] + require.NotNil(t, script) + t.Logf("script attributes: %#v", script.Primary.Attributes) + for key, expected := range map[string]string{ + "agent_id": "king", + "workspace_folder": "/workspace", + } { + require.Equal(t, expected, script.Primary.Attributes[key]) + } + return nil + }, + }}, + }) +} + +func TestDevcontainerNoWorkspaceFolder(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + ProviderFactories: coderFactory(), + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + } + resource "coder_devcontainer" "example" { + agent_id = "" + } + `, + ExpectError: regexp.MustCompile(`The argument "workspace_folder" is required, but no definition was found.`), + }}, + }) +} diff --git a/provider/provider.go b/provider/provider.go index d9780d7..cc2644e 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -76,6 +76,7 @@ func New() *schema.Provider { "coder_metadata": metadataResource(), "coder_script": scriptResource(), "coder_env": envResource(), + "coder_devcontainer": devcontainerResource(), }, } } From 5f970f86b1b43bc800da27015fbf2aaa9d22c1c3 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 20 Mar 2025 10:19:18 +0000 Subject: [PATCH 2/2] add comment for min version --- docs/resources/devcontainer.md | 4 ++-- provider/devcontainer.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/resources/devcontainer.md b/docs/resources/devcontainer.md index 896786d..93d5724 100644 --- a/docs/resources/devcontainer.md +++ b/docs/resources/devcontainer.md @@ -3,12 +3,12 @@ page_title: "coder_devcontainer Resource - terraform-provider-coder" subcategory: "" description: |- - Define a Dev Container the agent should know of and attempt to autostart. + Define a Dev Container the agent should know of and attempt to autostart (minimum Coder version: v2.21). --- # coder_devcontainer (Resource) -Define a Dev Container the agent should know of and attempt to autostart. +Define a Dev Container the agent should know of and attempt to autostart (minimum Coder version: v2.21). diff --git a/provider/devcontainer.go b/provider/devcontainer.go index bfe99f0..7d1fe0a 100644 --- a/provider/devcontainer.go +++ b/provider/devcontainer.go @@ -13,7 +13,7 @@ func devcontainerResource() *schema.Resource { return &schema.Resource{ SchemaVersion: 1, - Description: "Define a Dev Container the agent should know of and attempt to autostart.", + Description: "Define a Dev Container the agent should know of and attempt to autostart (minimum Coder version: v2.21).", CreateContext: func(_ context.Context, rd *schema.ResourceData, _ interface{}) diag.Diagnostics { rd.SetId(uuid.NewString())