diff --git a/docs/data-sources/workspace.md b/docs/data-sources/workspace.md index 8b824c37..26396ba1 100644 --- a/docs/data-sources/workspace.md +++ b/docs/data-sources/workspace.md @@ -13,11 +13,51 @@ Use this data source to get information for the active workspace build. ## Example Usage ```terraform -data "coder_workspace" "dev" { +provider "coder" {} + +provider "docker" {} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +resource "coder_agent" "dev" { + arch = "amd64" + os = "linux" + dir = "/workspace" } -resource "kubernetes_pod" "dev" { - count = data.coder_workspace.dev.transition == "start" ? 1 : 0 +resource "docker_container" "workspace" { + count = data.coder_workspace.me.start_count + image = docker_image.main.name + # Uses lower() to avoid Docker restriction on container names. + name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}" + # Hostname makes the shell more user friendly: coder@my-workspace:~$ + hostname = data.coder_workspace.me.name + # Use the docker gateway if the access URL is 127.0.0.1 + entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")] + env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"] + host { + host = "host.docker.internal" + ip = "host-gateway" + } + # Add labels in Docker to keep track of orphan resources. + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + labels { + label = "coder.workspace_name" + value = data.coder_workspace.me.name + } } ``` @@ -30,13 +70,6 @@ resource "kubernetes_pod" "dev" { - `access_url` (String) The access URL of the Coder deployment provisioning this workspace. - `id` (String) UUID of the workspace. - `name` (String) Name of the workspace. -- `owner` (String, **Deprecated**: Use `coder_workspace_owner.name` instead.) Username of the workspace owner. -- `owner_email` (String, **Deprecated**: Use `coder_workspace_owner.email` instead.) Email address of the workspace owner. -- `owner_groups` (List of String, **Deprecated**: Use `coder_workspace_owner.groups` instead.) List of groups the workspace owner belongs to. -- `owner_id` (String, **Deprecated**: Use `coder_workspace_owner.id` instead.) UUID of the workspace owner. -- `owner_name` (String, **Deprecated**: Use `coder_workspace_owner.full_name` instead.) Name of the workspace owner. -- `owner_oidc_access_token` (String, **Deprecated**: Use `coder_workspace_owner.oidc_access_token` instead.) 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, **Deprecated**: Use `coder_workspace_owner.session_token` instead.) 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. - `template_id` (String) ID of the workspace's template. - `template_name` (String) Name of the workspace's template. diff --git a/docs/data-sources/workspace_owner.md b/docs/data-sources/workspace_owner.md index 0deff622..1c64ea50 100644 --- a/docs/data-sources/workspace_owner.md +++ b/docs/data-sources/workspace_owner.md @@ -15,14 +15,12 @@ Use this data source to fetch information about the workspace owner. ```terraform provider "coder" {} -data "coder_workspace" "me" {} - data "coder_workspace_owner" "me" {} resource "coder_agent" "dev" { arch = "amd64" os = "linux" - dir = local.repo_dir + dir = "/workspace" env = { OIDC_TOKEN : data.coder_workspace_owner.me.oidc_access_token, } @@ -36,7 +34,7 @@ resource "coder_env" "git_author_name" { } resource "coder_env" "git_author_email" { - agent_id = var.agent_id + agent_id = coder_agent.dev.id name = "GIT_AUTHOR_EMAIL" value = data.coder_workspace_owner.me.email count = data.coder_workspace_owner.me.email != "" ? 1 : 0 diff --git a/examples/data-sources/coder_workspace/data-source.tf b/examples/data-sources/coder_workspace/data-source.tf index 4898439b..8eb4a8f8 100644 --- a/examples/data-sources/coder_workspace/data-source.tf +++ b/examples/data-sources/coder_workspace/data-source.tf @@ -1,6 +1,46 @@ -data "coder_workspace" "dev" { +provider "coder" {} + +provider "docker" {} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +resource "coder_agent" "dev" { + arch = "amd64" + os = "linux" + dir = "/workspace" } -resource "kubernetes_pod" "dev" { - count = data.coder_workspace.dev.transition == "start" ? 1 : 0 +resource "docker_container" "workspace" { + count = data.coder_workspace.me.start_count + image = docker_image.main.name + # Uses lower() to avoid Docker restriction on container names. + name = "coder-${data.coder_workspace_owner.me.name}-${lower(data.coder_workspace.me.name)}" + # Hostname makes the shell more user friendly: coder@my-workspace:~$ + hostname = data.coder_workspace.me.name + # Use the docker gateway if the access URL is 127.0.0.1 + entrypoint = ["sh", "-c", replace(coder_agent.main.init_script, "/localhost|127\\.0\\.0\\.1/", "host.docker.internal")] + env = ["CODER_AGENT_TOKEN=${coder_agent.main.token}"] + host { + host = "host.docker.internal" + ip = "host-gateway" + } + # Add labels in Docker to keep track of orphan resources. + labels { + label = "coder.owner" + value = data.coder_workspace_owner.me.name + } + labels { + label = "coder.owner_id" + value = data.coder_workspace_owner.me.id + } + labels { + label = "coder.workspace_id" + value = data.coder_workspace.me.id + } + labels { + label = "coder.workspace_name" + value = data.coder_workspace.me.name + } } diff --git a/examples/data-sources/coder_workspace_owner/data-source.tf b/examples/data-sources/coder_workspace_owner/data-source.tf index fc27db6c..cad73e1e 100644 --- a/examples/data-sources/coder_workspace_owner/data-source.tf +++ b/examples/data-sources/coder_workspace_owner/data-source.tf @@ -1,13 +1,11 @@ provider "coder" {} -data "coder_workspace" "me" {} - data "coder_workspace_owner" "me" {} resource "coder_agent" "dev" { arch = "amd64" os = "linux" - dir = local.repo_dir + dir = "/workspace" env = { OIDC_TOKEN : data.coder_workspace_owner.me.oidc_access_token, } @@ -21,7 +19,7 @@ resource "coder_env" "git_author_name" { } resource "coder_env" "git_author_email" { - agent_id = var.agent_id + agent_id = coder_agent.dev.id name = "GIT_AUTHOR_EMAIL" value = data.coder_workspace_owner.me.email count = data.coder_workspace_owner.me.email != "" ? 1 : 0 diff --git a/integration/integration_test.go b/integration/integration_test.go index 75b35d20..8208d20a 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -71,25 +71,18 @@ func TestIntegration(t *testing.T) { name: "test-data-source", minVersion: "v0.0.0", expectedOutput: map[string]string{ - "provisioner.arch": runtime.GOARCH, - "provisioner.id": `[a-zA-Z0-9-]+`, - "provisioner.os": runtime.GOOS, - "workspace.access_port": `\d+`, - "workspace.access_url": `https?://\D+:\d+`, - "workspace.id": `[a-zA-z0-9-]+`, - "workspace.name": `test-data-source`, - "workspace.owner": `testing`, - "workspace.owner_email": `testing@coder\.com`, - "workspace.owner_groups": `\[\]`, - "workspace.owner_id": `[a-zA-Z0-9]+`, - "workspace.owner_name": `default`, - "workspace.owner_oidc_access_token": `^$`, // TODO: need a test OIDC integration - "workspace.owner_session_token": `[a-zA-Z0-9-]+`, - "workspace.start_count": `1`, - "workspace.template_id": `[a-zA-Z0-9-]+`, - "workspace.template_name": `test-data-source`, - "workspace.template_version": `.+`, - "workspace.transition": `start`, + "provisioner.arch": runtime.GOARCH, + "provisioner.id": `[a-zA-Z0-9-]+`, + "provisioner.os": runtime.GOOS, + "workspace.access_port": `\d+`, + "workspace.access_url": `https?://\D+:\d+`, + "workspace.id": `[a-zA-z0-9-]+`, + "workspace.name": `test-data-source`, + "workspace.start_count": `1`, + "workspace.template_id": `[a-zA-Z0-9-]+`, + "workspace.template_name": `test-data-source`, + "workspace.template_version": `.+`, + "workspace.transition": `start`, }, }, { @@ -103,13 +96,6 @@ func TestIntegration(t *testing.T) { "workspace.access_url": `https?://\D+:\d+`, "workspace.id": `[a-zA-z0-9-]+`, "workspace.name": ``, - "workspace.owner": `testing`, - "workspace.owner_email": `testing@coder\.com`, - "workspace.owner_groups": `\[\]`, - "workspace.owner_id": `[a-zA-Z0-9]+`, - "workspace.owner_name": `default`, - "workspace.owner_oidc_access_token": `^$`, // TODO: need a test OIDC integration - "workspace.owner_session_token": `[a-zA-Z0-9-]+`, "workspace.start_count": `1`, "workspace.template_id": `[a-zA-Z0-9-]+`, "workspace.template_name": `workspace-owner`, diff --git a/integration/test-data-source/main.tf b/integration/test-data-source/main.tf index 838125a0..6d4b85cd 100644 --- a/integration/test-data-source/main.tf +++ b/integration/test-data-source/main.tf @@ -9,9 +9,8 @@ terraform { } } -// TODO: test coder_external_auth and coder_git_auth +// TODO: test coder_external_auth // data coder_external_auth "me" {} -// data coder_git_auth "me" {} data "coder_provisioner" "me" {} data "coder_workspace" "me" {} data "coder_workspace_owner" "me" {} @@ -26,13 +25,6 @@ locals { "workspace.access_url" : data.coder_workspace.me.access_url, "workspace.id" : data.coder_workspace.me.id, "workspace.name" : data.coder_workspace.me.name, - "workspace.owner" : data.coder_workspace.me.owner, - "workspace.owner_email" : data.coder_workspace.me.owner_email, - "workspace.owner_groups" : jsonencode(data.coder_workspace.me.owner_groups), - "workspace.owner_id" : data.coder_workspace.me.owner_id, - "workspace.owner_name" : data.coder_workspace.me.owner_name, - "workspace.owner_oidc_access_token" : data.coder_workspace.me.owner_oidc_access_token, - "workspace.owner_session_token" : data.coder_workspace.me.owner_session_token, "workspace.start_count" : tostring(data.coder_workspace.me.start_count), "workspace.template_id" : data.coder_workspace.me.template_id, "workspace.template_name" : data.coder_workspace.me.template_name, diff --git a/integration/workspace-owner/main.tf b/integration/workspace-owner/main.tf index 580592cb..2be11d8e 100644 --- a/integration/workspace-owner/main.tf +++ b/integration/workspace-owner/main.tf @@ -9,9 +9,8 @@ terraform { } } -// TODO: test coder_external_auth and coder_git_auth +// TODO: test coder_external_auth // data coder_external_auth "me" {} -// data coder_git_auth "me" {} data "coder_provisioner" "me" {} data "coder_workspace" "me" {} data "coder_workspace_owner" "me" {} @@ -26,13 +25,6 @@ locals { "workspace.access_url" : data.coder_workspace.me.access_url, "workspace.id" : data.coder_workspace.me.id, "workspace.name" : data.coder_workspace.me.name, - "workspace.owner" : data.coder_workspace.me.owner, - "workspace.owner_email" : data.coder_workspace.me.owner_email, - "workspace.owner_groups" : jsonencode(data.coder_workspace.me.owner_groups), - "workspace.owner_id" : data.coder_workspace.me.owner_id, - "workspace.owner_name" : data.coder_workspace.me.owner_name, - "workspace.owner_oidc_access_token" : data.coder_workspace.me.owner_oidc_access_token, - "workspace.owner_session_token" : data.coder_workspace.me.owner_session_token, "workspace.start_count" : tostring(data.coder_workspace.me.start_count), "workspace.template_id" : data.coder_workspace.me.template_id, "workspace.template_name" : data.coder_workspace.me.template_name, diff --git a/provider/workspace.go b/provider/workspace.go index 3f667e8f..575fd60f 100644 --- a/provider/workspace.go +++ b/provider/workspace.go @@ -2,7 +2,6 @@ package provider import ( "context" - "encoding/json" "reflect" "strconv" @@ -28,37 +27,9 @@ func workspaceDataSource() *schema.Resource { } _ = rd.Set("start_count", count) - owner := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER", "default") - _ = rd.Set("owner", owner) - - ownerEmail := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER_EMAIL", "default@example.com") - _ = rd.Set("owner_email", ownerEmail) - - ownerGroupsText := helpers.OptionalEnv("CODER_WORKSPACE_OWNER_GROUPS") - var ownerGroups []string - if ownerGroupsText != "" { - err := json.Unmarshal([]byte(ownerGroupsText), &ownerGroups) - if err != nil { - return diag.Errorf("couldn't parse owner groups %q", ownerGroupsText) - } - } - _ = rd.Set("owner_groups", ownerGroups) - - ownerName := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER_NAME", "default") - _ = rd.Set("owner_name", ownerName) - - ownerID := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_OWNER_ID", uuid.Nil.String()) - _ = rd.Set("owner_id", ownerID) - - ownerOIDCAccessToken := helpers.OptionalEnv("CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN") - _ = rd.Set("owner_oidc_access_token", ownerOIDCAccessToken) - name := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_NAME", "default") rd.Set("name", name) - sessionToken := helpers.OptionalEnv("CODER_WORKSPACE_OWNER_SESSION_TOKEN") - _ = rd.Set("owner_session_token", sessionToken) - id := helpers.OptionalEnvOrDefault("CODER_WORKSPACE_ID", uuid.NewString()) rd.SetId(id) @@ -122,47 +93,6 @@ func workspaceDataSource() *schema.Resource { Computed: true, Description: "Either `start` or `stop`. Use this to start/stop resources with `count`.", }, - "owner": { - Type: schema.TypeString, - Computed: true, - Description: "Username of the workspace owner.", - Deprecated: "Use `coder_workspace_owner.name` instead.", - }, - "owner_email": { - Type: schema.TypeString, - Computed: true, - Description: "Email address of the workspace owner.", - Deprecated: "Use `coder_workspace_owner.email` instead.", - }, - "owner_id": { - Type: schema.TypeString, - Computed: true, - Description: "UUID of the workspace owner.", - Deprecated: "Use `coder_workspace_owner.id` instead.", - }, - "owner_name": { - Type: schema.TypeString, - Computed: true, - Description: "Name of the workspace owner.", - Deprecated: "Use `coder_workspace_owner.full_name` instead.", - }, - "owner_oidc_access_token": { - Type: schema.TypeString, - Computed: true, - Description: "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.", - Deprecated: "Use `coder_workspace_owner.oidc_access_token` instead.", - }, - "owner_groups": { - Type: schema.TypeList, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Computed: true, - Description: "List of groups the workspace owner belongs to.", - Deprecated: "Use `coder_workspace_owner.groups` instead.", - }, "id": { Type: schema.TypeString, Computed: true, @@ -173,12 +103,6 @@ func workspaceDataSource() *schema.Resource { Computed: true, Description: "Name of the workspace.", }, - "owner_session_token": { - Type: schema.TypeString, - Computed: true, - Description: "Session token for authenticating with a Coder deployment. It is regenerated everytime a workspace is started.", - Deprecated: "Use `coder_workspace_owner.session_token` instead.", - }, "template_id": { Type: schema.TypeString, Computed: true, diff --git a/provider/workspace_test.go b/provider/workspace_test.go index e53f30d4..12d5210b 100644 --- a/provider/workspace_test.go +++ b/provider/workspace_test.go @@ -14,13 +14,6 @@ import ( ) func TestWorkspace(t *testing.T) { - t.Setenv("CODER_WORKSPACE_OWNER", "owner123") - t.Setenv("CODER_WORKSPACE_OWNER_ID", "11111111-1111-1111-1111-111111111111") - t.Setenv("CODER_WORKSPACE_OWNER_NAME", "Mr Owner") - t.Setenv("CODER_WORKSPACE_OWNER_EMAIL", "owner123@example.com") - t.Setenv("CODER_WORKSPACE_OWNER_SESSION_TOKEN", "abc123") - t.Setenv("CODER_WORKSPACE_OWNER_GROUPS", `["group1", "group2"]`) - t.Setenv("CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN", "supersecret") t.Setenv("CODER_WORKSPACE_TEMPLATE_ID", "templateID") t.Setenv("CODER_WORKSPACE_TEMPLATE_NAME", "template123") t.Setenv("CODER_WORKSPACE_TEMPLATE_VERSION", "v1.2.3") @@ -49,16 +42,9 @@ func TestWorkspace(t *testing.T) { t.Log(value) assert.Equal(t, "https://example.com:8080", attribs["access_url"]) assert.Equal(t, "8080", attribs["access_port"]) - assert.Equal(t, "owner123", attribs["owner"]) - assert.Equal(t, "11111111-1111-1111-1111-111111111111", attribs["owner_id"]) - assert.Equal(t, "Mr Owner", attribs["owner_name"]) - assert.Equal(t, "owner123@example.com", attribs["owner_email"]) - assert.Equal(t, "group1", attribs["owner_groups.0"]) - assert.Equal(t, "group2", attribs["owner_groups.1"]) assert.Equal(t, "templateID", attribs["template_id"]) assert.Equal(t, "template123", attribs["template_name"]) assert.Equal(t, "v1.2.3", attribs["template_version"]) - assert.Equal(t, "supersecret", attribs["owner_oidc_access_token"]) return nil }, }}, @@ -66,9 +52,6 @@ func TestWorkspace(t *testing.T) { } func TestWorkspace_UndefinedOwner(t *testing.T) { - t.Setenv("CODER_WORKSPACE_OWNER", "owner123") - t.Setenv("CODER_WORKSPACE_OWNER_SESSION_TOKEN", "abc123") - t.Setenv("CODER_WORKSPACE_OWNER_GROUPS", `["group1", "group2"]`) t.Setenv("CODER_WORKSPACE_TEMPLATE_ID", "templateID") t.Setenv("CODER_WORKSPACE_TEMPLATE_NAME", "template123") t.Setenv("CODER_WORKSPACE_TEMPLATE_VERSION", "v1.2.3") @@ -95,8 +78,9 @@ func TestWorkspace_UndefinedOwner(t *testing.T) { value := attribs["transition"] require.NotNil(t, value) t.Log(value) - assert.Equal(t, "owner123", attribs["owner"]) - assert.Equal(t, "default@example.com", attribs["owner_email"]) + assert.Equal(t, "templateID", attribs["template_id"]) + assert.Equal(t, "template123", attribs["template_name"]) + assert.Equal(t, "v1.2.3", attribs["template_version"]) // Skip other asserts return nil }, @@ -107,13 +91,6 @@ func TestWorkspace_UndefinedOwner(t *testing.T) { func TestWorkspace_MissingTemplateName(t *testing.T) { t.Setenv("CODER_WORKSPACE_BUILD_ID", "1") // Let's pretend this is a workspace build - t.Setenv("CODER_WORKSPACE_OWNER", "owner123") - t.Setenv("CODER_WORKSPACE_OWNER_ID", "11111111-1111-1111-1111-111111111111") - t.Setenv("CODER_WORKSPACE_OWNER_NAME", "Mr Owner") - t.Setenv("CODER_WORKSPACE_OWNER_EMAIL", "owner123@example.com") - t.Setenv("CODER_WORKSPACE_OWNER_SESSION_TOKEN", "abc123") - t.Setenv("CODER_WORKSPACE_OWNER_GROUPS", `["group1", "group2"]`) - t.Setenv("CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN", "supersecret") t.Setenv("CODER_WORKSPACE_TEMPLATE_ID", "templateID") // CODER_WORKSPACE_TEMPLATE_NAME is missing t.Setenv("CODER_WORKSPACE_TEMPLATE_VERSION", "v1.2.3")