diff --git a/docs/data-sources/workspace.md b/docs/data-sources/workspace.md
index e7d58a5d..c736f78a 100644
--- a/docs/data-sources/workspace.md
+++ b/docs/data-sources/workspace.md
@@ -34,6 +34,6 @@ resource "kubernetes_pod" "dev" {
- `owner_email` (String) Email address of the workspace owner.
- `owner_id` (String) UUID of the workspace owner.
- `owner_oidc_access_token` (String) A valid OpenID Connect access token of the workspace owner. This is only available if the workspace owner authenticated with OpenID Connect. If a valid token cannot be obtained, this value will be an empty string.
-- `owner_session_token` (String) Session token for interfacing with a Coder deployment. It is regenerated everytime a workspace is started.
+- `owner_session_token` (String) Session token for authenticating with a Coder deployment. It is regenerated everytime a workspace is started.
- `start_count` (Number) A computed count based on "transition" state. If "start", count will equal 1.
- `transition` (String) Either "start" or "stop". Use this to start/stop resources with "count".
diff --git a/docs/resources/agent.md b/docs/resources/agent.md
index d073f7c5..7e20ade4 100644
--- a/docs/resources/agent.md
+++ b/docs/resources/agent.md
@@ -20,6 +20,12 @@ resource "coder_agent" "dev" {
os = "linux"
arch = "amd64"
dir = "/workspace"
+ display_apps {
+ vscode = true
+ vscode_insiders = false
+ web_terminal = true
+ ssh_helper = false
+ }
}
resource "kubernetes_pod" "dev" {
@@ -49,6 +55,7 @@ resource "kubernetes_pod" "dev" {
- `auth` (String) The authentication type the agent will use. Must be one of: "token", "google-instance-identity", "aws-instance-identity", "azure-instance-identity".
- `connection_timeout` (Number) Time in seconds until the agent is marked as timed out when a connection with the server cannot be established. A value of zero never marks the agent as timed out.
- `dir` (String) The starting directory when a user creates a shell session. Defaults to $HOME.
+- `display_apps` (Block Set, Max: 1) The list of built-in apps to display in the agent bar. (see [below for nested schema](#nestedblock--display_apps))
- `env` (Map of String) A mapping of environment variables to set inside the workspace.
- `login_before_ready` (Boolean, Deprecated) This option defines whether or not the user can (by default) login to the workspace before it is ready. Ready means that e.g. the startup_script is done and has exited. When enabled, users may see an incomplete workspace when logging in.
- `metadata` (Block List) Each "metadata" block defines a single item consisting of a key/value pair. This feature is in alpha and may break in future releases. (see [below for nested schema](#nestedblock--metadata))
@@ -66,6 +73,18 @@ resource "kubernetes_pod" "dev" {
- `init_script` (String) Run this script on startup of an instance to initialize the agent.
- `token` (String, Sensitive) Set the environment variable "CODER_AGENT_TOKEN" with this token to authenticate an agent.
+
+### Nested Schema for `display_apps`
+
+Optional:
+
+- `port_forwarding_helper` (Boolean) Display the port-forwarding helper button in the agent bar.
+- `ssh_helper` (Boolean) Display the SSH helper button in the agent bar.
+- `vscode` (Boolean) Display the VSCode Desktop app in the agent bar.
+- `vscode_insiders` (Boolean) Display the VSCode Insiders app in the agent bar.
+- `web_terminal` (Boolean) Display the web terminal app in the agent bar.
+
+
### Nested Schema for `metadata`
diff --git a/examples/resources/coder_agent/resource.tf b/examples/resources/coder_agent/resource.tf
index 2f1503fd..d5235a18 100644
--- a/examples/resources/coder_agent/resource.tf
+++ b/examples/resources/coder_agent/resource.tf
@@ -5,6 +5,12 @@ resource "coder_agent" "dev" {
os = "linux"
arch = "amd64"
dir = "/workspace"
+ display_apps {
+ vscode = true
+ vscode_insiders = false
+ web_terminal = true
+ ssh_helper = false
+ }
}
resource "kubernetes_pod" "dev" {
diff --git a/provider/agent.go b/provider/agent.go
index 90dd0525..9b5ac3f3 100644
--- a/provider/agent.go
+++ b/provider/agent.go
@@ -23,6 +23,21 @@ func agentResource() *schema.Resource {
if err != nil {
return diag.FromErr(err)
}
+
+ if _, ok := resourceData.GetOk("display_apps"); !ok {
+ err = resourceData.Set("display_apps", []interface{}{
+ map[string]bool{
+ "vscode": true,
+ "vscode_insiders": false,
+ "web_terminal": true,
+ "ssh_helper": true,
+ "port_forwarding_helper": true,
+ },
+ })
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
return updateInitScript(resourceData, i)
},
ReadWithoutTimeout: func(ctx context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
@@ -30,6 +45,21 @@ func agentResource() *schema.Resource {
if err != nil {
return diag.FromErr(err)
}
+ if _, ok := resourceData.GetOk("display_apps"); !ok {
+ err = resourceData.Set("display_apps", []interface{}{
+ map[string]bool{
+ "vscode": true,
+ "vscode_insiders": false,
+ "web_terminal": true,
+ "ssh_helper": true,
+ "port_forwarding_helper": true,
+ },
+ })
+ if err != nil {
+ return diag.FromErr(err)
+ }
+ }
+
return updateInitScript(resourceData, i)
},
DeleteContext: func(ctx context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics {
@@ -198,6 +228,53 @@ func agentResource() *schema.Resource {
},
},
},
+ "display_apps": {
+ Type: schema.TypeSet,
+ Description: "The list of built-in apps to display in the agent bar.",
+ ForceNew: true,
+ Optional: true,
+ MaxItems: 1,
+ Computed: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "vscode": {
+ Type: schema.TypeBool,
+ Description: "Display the VSCode Desktop app in the agent bar.",
+ ForceNew: true,
+ Optional: true,
+ Default: true,
+ },
+ "vscode_insiders": {
+ Type: schema.TypeBool,
+ Description: "Display the VSCode Insiders app in the agent bar.",
+ ForceNew: true,
+ Optional: true,
+ Default: false,
+ },
+ "web_terminal": {
+ Type: schema.TypeBool,
+ Description: "Display the web terminal app in the agent bar.",
+ ForceNew: true,
+ Optional: true,
+ Default: true,
+ },
+ "port_forwarding_helper": {
+ Type: schema.TypeBool,
+ Description: "Display the port-forwarding helper button in the agent bar.",
+ ForceNew: true,
+ Optional: true,
+ Default: true,
+ },
+ "ssh_helper": {
+ Type: schema.TypeBool,
+ Description: "Display the SSH helper button in the agent bar.",
+ ForceNew: true,
+ Optional: true,
+ Default: true,
+ },
+ },
+ },
+ },
},
}
}
diff --git a/provider/agent_test.go b/provider/agent_test.go
index e3d96d1b..9026385c 100644
--- a/provider/agent_test.go
+++ b/provider/agent_test.go
@@ -1,14 +1,16 @@
package provider_test
import (
+ "fmt"
"regexp"
"testing"
- "github.com/coder/terraform-provider-coder/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/stretchr/testify/require"
+
+ "github.com/coder/terraform-provider-coder/provider"
)
func TestAgent(t *testing.T) {
@@ -247,3 +249,181 @@ func TestAgent_Metadata(t *testing.T) {
}},
})
}
+
+func TestAgent_DisplayApps(t *testing.T) {
+ t.Parallel()
+ t.Run("OK", func(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ Providers: map[string]*schema.Provider{
+ "coder": provider.New(),
+ },
+ IsUnitTest: true,
+ Steps: []resource.TestStep{{
+ // Test the fields with non-default values.
+ Config: `
+ provider "coder" {
+ url = "https://example.com"
+ }
+ resource "coder_agent" "dev" {
+ os = "linux"
+ arch = "amd64"
+ display_apps {
+ vscode = false
+ vscode_insiders = true
+ web_terminal = false
+ port_forwarding_helper = false
+ ssh_helper = false
+ }
+ }
+ `,
+ Check: func(state *terraform.State) error {
+ require.Len(t, state.Modules, 1)
+ require.Len(t, state.Modules[0].Resources, 1)
+
+ resource := state.Modules[0].Resources["coder_agent.dev"]
+ require.NotNil(t, resource)
+
+ t.Logf("resource: %v", resource.Primary.Attributes)
+
+ for _, app := range []string{
+ "web_terminal",
+ "vscode_insiders",
+ "vscode",
+ "port_forwarding_helper",
+ "ssh_helper",
+ } {
+ key := fmt.Sprintf("display_apps.0.%s", app)
+ if app == "vscode_insiders" {
+ require.Equal(t, "true", resource.Primary.Attributes[key])
+ } else {
+ require.Equal(t, "false", resource.Primary.Attributes[key])
+ }
+ }
+ return nil
+ },
+ }},
+ })
+ })
+
+ t.Run("Subset", func(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ Providers: map[string]*schema.Provider{
+ "coder": provider.New(),
+ },
+ IsUnitTest: true,
+ Steps: []resource.TestStep{{
+ // Test the fields with non-default values.
+ Config: `
+ provider "coder" {
+ url = "https://example.com"
+ }
+ resource "coder_agent" "dev" {
+ os = "linux"
+ arch = "amd64"
+ display_apps {
+ vscode_insiders = true
+ web_terminal = true
+ }
+ }
+ `,
+ Check: func(state *terraform.State) error {
+ require.Len(t, state.Modules, 1)
+ require.Len(t, state.Modules[0].Resources, 1)
+
+ resource := state.Modules[0].Resources["coder_agent.dev"]
+ require.NotNil(t, resource)
+
+ t.Logf("resource: %v", resource.Primary.Attributes)
+
+ for _, app := range []string{
+ "web_terminal",
+ "vscode_insiders",
+ "vscode",
+ "port_forwarding_helper",
+ "ssh_helper",
+ } {
+ key := fmt.Sprintf("display_apps.0.%s", app)
+ require.Equal(t, "true", resource.Primary.Attributes[key])
+ }
+ return nil
+ },
+ }},
+ })
+ })
+
+ // Assert all the defaults are set correctly.
+ t.Run("Omitted", func(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ Providers: map[string]*schema.Provider{
+ "coder": provider.New(),
+ },
+ IsUnitTest: true,
+ Steps: []resource.TestStep{{
+ Config: `
+ provider "coder" {
+ url = "https://example.com"
+ }
+ resource "coder_agent" "dev" {
+ os = "linux"
+ arch = "amd64"
+ }
+ `,
+ Check: func(state *terraform.State) error {
+ require.Len(t, state.Modules, 1)
+ require.Len(t, state.Modules[0].Resources, 1)
+
+ resource := state.Modules[0].Resources["coder_agent.dev"]
+ require.NotNil(t, resource)
+
+ t.Logf("resource: %v", resource.Primary.Attributes)
+
+ for _, app := range []string{
+ "web_terminal",
+ "vscode_insiders",
+ "vscode",
+ "port_forwarding_helper",
+ "ssh_helper",
+ } {
+ key := fmt.Sprintf("display_apps.0.%s", app)
+ if app == "vscode_insiders" {
+ require.Equal(t, "false", resource.Primary.Attributes[key])
+ } else {
+ require.Equal(t, "true", resource.Primary.Attributes[key])
+ }
+ }
+ return nil
+ },
+ }},
+ })
+ })
+
+ t.Run("InvalidApp", func(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ Providers: map[string]*schema.Provider{
+ "coder": provider.New(),
+ },
+ IsUnitTest: true,
+ Steps: []resource.TestStep{{
+ // Test the fields with non-default values.
+ Config: `
+ provider "coder" {
+ url = "https://example.com"
+ }
+ resource "coder_agent" "dev" {
+ os = "linux"
+ arch = "amd64"
+ display_apps {
+ fake_app = false
+ vscode_insiders = true
+ web_terminal = false
+ port_forwarding_helper = false
+ ssh_helper = false
+ }
+ }
+ `,
+ ExpectError: regexp.MustCompile(`An argument named "fake_app" is not expected here.`),
+ }},
+ })
+ })
+
+}
diff --git a/provider/examples_test.go b/provider/examples_test.go
index 263e65ce..9be7ce02 100644
--- a/provider/examples_test.go
+++ b/provider/examples_test.go
@@ -4,10 +4,11 @@ import (
"os"
"testing"
- "github.com/coder/terraform-provider-coder/provider"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/stretchr/testify/require"
+
+ "github.com/coder/terraform-provider-coder/provider"
)
func TestExamples(t *testing.T) {
diff --git a/provider/workspace.go b/provider/workspace.go
index 47f0e799..995cb6e4 100644
--- a/provider/workspace.go
+++ b/provider/workspace.go
@@ -137,7 +137,7 @@ func workspaceDataSource() *schema.Resource {
"owner_session_token": {
Type: schema.TypeString,
Computed: true,
- Description: "Session token for interfacing with a Coder deployment. It is regenerated everytime a workspace is started.",
+ Description: "Session token for authenticating with a Coder deployment. It is regenerated everytime a workspace is started.",
},
},
}