From fb71cb5f9688b93ac53a050e668586814269f06a Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 14:51:07 +0500 Subject: [PATCH 1/9] fix: fix broken troubleshooting link (cherry-pick #16469) (#16472) Co-authored-by: Marcin Tojek fix: fix broken troubleshooting link (#16469) Fixes: https://github.com/coder/coder/issues/16468 --- cli/ping.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/ping.go b/cli/ping.go index 0e219d5762f86..19191b92916bb 100644 --- a/cli/ping.go +++ b/cli/ping.go @@ -159,7 +159,7 @@ func (r *RootCmd) ping() *serpent.Command { LocalNetInfo: ni, Verbose: r.verbose, PingP2P: didP2p, - TroubleshootingURL: appearanceConfig.DocsURL + "/networking/troubleshooting", + TroubleshootingURL: appearanceConfig.DocsURL + "/admin/networking/troubleshooting", } awsRanges, err := cliutil.FetchAWSIPRanges(diagCtx, cliutil.AWSIPRangesURL) From 552c4cd93d6e89bc6631cefbc5e4ecf4e59c84d2 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:08:59 +0500 Subject: [PATCH 2/9] fix: handle undefined job while updating build progress (cherry-pick #16732) (#16741) Cherry-picked fix: handle undefined job while updating build progress (#16732) Fixes: https://github.com/coder/coder/issues/15444 Co-authored-by: Marcin Tojek --- site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx index 88f006681495e..52f3e725c6003 100644 --- a/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceBuildProgress.tsx @@ -81,6 +81,7 @@ export const WorkspaceBuildProgress: FC = ({ useEffect(() => { const updateProgress = () => { if ( + job === undefined || job.status !== "running" || transitionStats.P50 === undefined || transitionStats.P95 === undefined || From d31c994018e2639264b05a1f6d0eeaec2852a77c Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 4 Mar 2025 17:12:12 -0500 Subject: [PATCH 3/9] chore: upgrade terraform to 1.10.5 (#16519) (#16806) - Updates `terraform` to [v1.10.5](https://github.com/hashicorp/terraform/blob/v1.10.5/CHANGELOG.md#1105-january-22-2025) - Updates provider to >=2.0.0 in provider testdata fixtures - Fixes provider to required release version for resource monitors - Fixes missing leading / in volumes in resource monitor tests --------- --------- Co-authored-by: Colin Adler Co-authored-by: Cian Johnston --- .github/actions/setup-tf/action.yaml | 2 +- docs/install/offline.md | 2 +- dogfood/contents/Dockerfile | 4 +- install.sh | 2 +- provisioner/terraform/install.go | 4 +- .../testdata/calling-module/calling-module.tf | 2 +- .../calling-module/calling-module.tfplan.json | 20 +- .../calling-module.tfstate.json | 17 +- .../chaining-resources/chaining-resources.tf | 2 +- .../chaining-resources.tfplan.json | 20 +- .../chaining-resources.tfstate.json | 17 +- .../conflicting-resources.tf | 2 +- .../conflicting-resources.tfplan.json | 20 +- .../conflicting-resources.tfstate.json | 17 +- .../display-apps-disabled.tf | 2 +- .../display-apps-disabled.tfplan.json | 20 +- .../display-apps-disabled.tfstate.json | 15 +- .../testdata/display-apps/display-apps.tf | 2 +- .../display-apps/display-apps.tfplan.json | 20 +- .../display-apps/display-apps.tfstate.json | 15 +- .../external-auth-providers.tf | 2 +- .../external-auth-providers.tfplan.json | 22 +- .../external-auth-providers.tfstate.json | 15 +- .../git-auth-providers.tfplan.json | 6 +- .../git-auth-providers.tfstate.json | 8 +- .../testdata/instance-id/instance-id.tf | 2 +- .../instance-id/instance-id.tfplan.json | 20 +- .../instance-id/instance-id.tfstate.json | 19 +- .../kubernetes-metadata.tf | 2 +- .../testdata/mapped-apps/mapped-apps.tf | 2 +- .../mapped-apps/mapped-apps.tfplan.json | 42 +- .../mapped-apps/mapped-apps.tfstate.json | 35 +- .../multiple-agents-multiple-apps.tf | 2 +- .../multiple-agents-multiple-apps.tfplan.json | 70 +- ...multiple-agents-multiple-apps.tfstate.json | 58 +- .../multiple-agents-multiple-envs.tf | 2 +- .../multiple-agents-multiple-envs.tfplan.json | 46 +- ...multiple-agents-multiple-envs.tfstate.json | 46 +- .../multiple-agents-multiple-monitors.tf | 67 ++ ...tiple-agents-multiple-monitors.tfplan.json | 625 ++++++++++++++++++ ...iple-agents-multiple-monitors.tfstate.json | 231 +++++++ .../multiple-agents-multiple-scripts.tf | 2 +- ...ltiple-agents-multiple-scripts.tfplan.json | 50 +- ...tiple-agents-multiple-scripts.tfstate.json | 46 +- .../multiple-agents.tfplan.json | 4 +- .../multiple-agents.tfstate.json | 20 +- .../testdata/multiple-apps/multiple-apps.tf | 2 +- .../multiple-apps/multiple-apps.tfplan.json | 56 +- .../multiple-apps/multiple-apps.tfstate.json | 45 +- .../resource-metadata-duplicate.tf | 2 +- .../resource-metadata-duplicate.tfplan.json | 28 +- .../resource-metadata-duplicate.tfstate.json | 27 +- .../resource-metadata/resource-metadata.tf | 2 +- .../resource-metadata.tfplan.json | 24 +- .../resource-metadata.tfstate.json | 21 +- .../rich-parameters-order.tf | 2 +- .../rich-parameters-order.tfplan.json | 26 +- .../rich-parameters-order.tfstate.json | 19 +- .../rich-parameters-validation.tf | 2 +- .../rich-parameters-validation.tfplan.json | 34 +- .../rich-parameters-validation.tfstate.json | 27 +- .../child-external-module/main.tf | 2 +- .../rich-parameters/external-module/main.tf | 2 +- .../rich-parameters/rich-parameters.tf | 2 +- .../rich-parameters.tfplan.json | 42 +- .../rich-parameters.tfstate.json | 35 +- provisioner/terraform/testdata/version.txt | 2 +- scripts/Dockerfile.base | 2 +- 68 files changed, 1398 insertions(+), 655 deletions(-) create mode 100644 provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf create mode 100644 provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json create mode 100644 provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json diff --git a/.github/actions/setup-tf/action.yaml b/.github/actions/setup-tf/action.yaml index c52f1138e03ca..f130bcdb7d028 100644 --- a/.github/actions/setup-tf/action.yaml +++ b/.github/actions/setup-tf/action.yaml @@ -7,5 +7,5 @@ runs: - name: Install Terraform uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 with: - terraform_version: 1.9.8 + terraform_version: 1.10.5 terraform_wrapper: false diff --git a/docs/install/offline.md b/docs/install/offline.md index 6a41bd9437894..0f83ae4077ee4 100644 --- a/docs/install/offline.md +++ b/docs/install/offline.md @@ -54,7 +54,7 @@ RUN mkdir -p /opt/terraform # The below step is optional if you wish to keep the existing version. # See https://github.com/coder/coder/blob/main/provisioner/terraform/install.go#L23-L24 # for supported Terraform versions. -ARG TERRAFORM_VERSION=1.9.8 +ARG TERRAFORM_VERSION=1.10.5 RUN apk update && \ apk del terraform && \ curl -LOs https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \ diff --git a/dogfood/contents/Dockerfile b/dogfood/contents/Dockerfile index 2de358c5c91e6..8c3613f59d468 100644 --- a/dogfood/contents/Dockerfile +++ b/dogfood/contents/Dockerfile @@ -195,9 +195,9 @@ RUN apt-get update --quiet && apt-get install --yes \ # Configure FIPS-compliant policies update-crypto-policies --set FIPS -# NOTE: In scripts/Dockerfile.base we specifically install Terraform version 1.9.8. +# NOTE: In scripts/Dockerfile.base we specifically install Terraform version 1.10.5. # Installing the same version here to match. -RUN wget -O /tmp/terraform.zip "https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_linux_amd64.zip" && \ +RUN wget -O /tmp/terraform.zip "https://releases.hashicorp.com/terraform/1.10.5/terraform_1.10.5_linux_amd64.zip" && \ unzip /tmp/terraform.zip -d /usr/local/bin && \ rm -f /tmp/terraform.zip && \ chmod +x /usr/local/bin/terraform && \ diff --git a/install.sh b/install.sh index 734fd3c44f320..931426c54c5db 100755 --- a/install.sh +++ b/install.sh @@ -273,7 +273,7 @@ EOF main() { MAINLINE=1 STABLE=0 - TERRAFORM_VERSION="1.9.8" + TERRAFORM_VERSION="1.10.5" if [ "${TRACE-}" ]; then set -x diff --git a/provisioner/terraform/install.go b/provisioner/terraform/install.go index 7f6474d022ba1..74229c8539bc0 100644 --- a/provisioner/terraform/install.go +++ b/provisioner/terraform/install.go @@ -20,10 +20,10 @@ var ( // when Terraform is not available on the system. // NOTE: Keep this in sync with the version in scripts/Dockerfile.base. // NOTE: Keep this in sync with the version in install.sh. - TerraformVersion = version.Must(version.NewVersion("1.9.8")) + TerraformVersion = version.Must(version.NewVersion("1.10.5")) minTerraformVersion = version.Must(version.NewVersion("1.1.0")) - maxTerraformVersion = version.Must(version.NewVersion("1.9.9")) // use .9 to automatically allow patch releases + maxTerraformVersion = version.Must(version.NewVersion("1.10.9")) // use .9 to automatically allow patch releases terraformMinorVersionMismatch = xerrors.New("Terraform binary minor version mismatch.") ) diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tf b/provisioner/terraform/testdata/calling-module/calling-module.tf index 14777169d9994..33fcbb3f1984f 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tf +++ b/provisioner/terraform/testdata/calling-module/calling-module.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json index 30bc360bb1940..31faf235810fa 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -90,16 +87,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -177,7 +171,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "module.module:null": { "name": "null", @@ -201,7 +195,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 } ], "module_calls": { @@ -260,7 +254,7 @@ ] } ], - "timestamp": "2024-10-28T20:07:49Z", + "timestamp": "2025-03-04T19:25:00Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json index 5ead2c6ace0d5..5a6b65b4d08ce 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "04d66dc4-e25a-4f65-af6f-a9af6b907430", + "id": "8632f695-0881-4df5-999c-ff105e2a62a4", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "10fbd765-b0cc-4d6f-b5de-e5a036b2cb4b", + "startup_script_behavior": "non-blocking", + "token": "18782be6-3080-42a8-bec4-b2e0cb4caf93", "troubleshooting_url": null }, "sensitive_values": { @@ -69,7 +66,7 @@ "outputs": { "script": "" }, - "random": "7917595776755902204" + "random": "735568859568633344" }, "sensitive_values": { "inputs": {}, @@ -84,7 +81,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2669991968036854745", + "id": "280446487996139212", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf index 3f210452dfee0..6ad44a62de986 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json index 38af6827019e7..b143b45e90fce 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -80,16 +77,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -155,7 +149,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -178,7 +172,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.a", @@ -205,7 +199,7 @@ ] } }, - "timestamp": "2024-10-28T20:07:50Z", + "timestamp": "2025-03-04T19:25:02Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json index 0cee8567db250..7681bf7d6b50c 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "bcf4bae1-0870-48e9-8bb4-af2f652c4d54", + "id": "c58b518a-428d-44b2-bfd7-1ac17188c528", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "afe98f25-25a2-4892-b921-be04bcd71efc", + "startup_script_behavior": "non-blocking", + "token": "085fd3ad-9462-4f9c-8f0f-05941d6cbc90", "troubleshooting_url": null }, "sensitive_values": { @@ -57,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "6598177855275264799", + "id": "2593580341963886034", "triggers": null }, "sensitive_values": {}, @@ -74,7 +71,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4663187895457986148", + "id": "8775084967398626100", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf index 8c7b200fca7b0..86585b6a85357 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json index 3fe9f6c41fa9b..ba67f290022c0 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -80,16 +77,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -155,7 +149,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -178,7 +172,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.first", @@ -205,7 +199,7 @@ ] } }, - "timestamp": "2024-10-28T20:07:52Z", + "timestamp": "2025-03-04T19:25:04Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json index ffd0690db2263..fdc0f8b1d062a 100644 --- a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "d047c7b6-b69e-4029-ab82-67468a0364f7", + "id": "bdf2fe69-0a3d-4aac-80c9-0896b0362d81", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "ceff37e3-52b9-4c80-af1b-1f9f99184590", + "startup_script_behavior": "non-blocking", + "token": "1428ac88-6dd9-4520-9c5c-0946fec8466b", "troubleshooting_url": null }, "sensitive_values": { @@ -57,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3120105803817695206", + "id": "3464200430566318947", "triggers": null }, "sensitive_values": {}, @@ -73,7 +70,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2942451035046396496", + "id": "4854441548409483963", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tf b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tf index 494e0acafb48f..155b81889540e 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tf +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json index 598d6f1735a84..00e14d332bcf7 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,16 +26,13 @@ } ], "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -88,16 +85,13 @@ } ], "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -146,7 +140,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -188,7 +182,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -204,7 +198,7 @@ ] } }, - "timestamp": "2024-10-28T20:07:55Z", + "timestamp": "2025-03-04T19:25:06Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json index 7e9bdad7a02bb..b85deea275dae 100644 --- a/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json +++ b/provisioner/terraform/testdata/display-apps-disabled/display-apps-disabled.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "6ba13739-4a9c-456f-90cf-feba8f194853", + "id": "a443e5e2-d59e-456d-95ff-b15685a37ebd", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "6e348a4c-ef00-40ab-9732-817fb828045c", + "startup_script_behavior": "non-blocking", + "token": "5407b786-d16b-4e64-abfa-75bc641fa6c3", "troubleshooting_url": null }, "sensitive_values": { @@ -57,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3123606937441446452", + "id": "1848001870879012103", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tf b/provisioner/terraform/testdata/display-apps/display-apps.tf index a36b68cd3b1cc..3544ab535ad2f 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tf +++ b/provisioner/terraform/testdata/display-apps/display-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json b/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json index 3331a8f282c2b..e79b567562e7c 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json +++ b/provisioner/terraform/testdata/display-apps/display-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,16 +26,13 @@ } ], "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -88,16 +85,13 @@ } ], "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -146,7 +140,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -188,7 +182,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -204,7 +198,7 @@ ] } }, - "timestamp": "2024-10-28T20:07:54Z", + "timestamp": "2025-03-04T19:25:08Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json b/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json index 2b04222e751f2..6cbccd0b8ea8a 100644 --- a/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json +++ b/provisioner/terraform/testdata/display-apps/display-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "b7e8dd7a-34aa-41e2-977e-e38577ab2476", + "id": "7399a566-8666-4a7b-a916-5043ea8b5a39", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "c6aeeb35-2766-4524-9818-687f7687831d", + "startup_script_behavior": "non-blocking", + "token": "47650163-1c1b-431b-81d6-42991663f53b", "troubleshooting_url": null }, "sensitive_values": { @@ -57,7 +54,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2407243137316459395", + "id": "1536600762010500828", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tf b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tf index 0b68bbe5710fe..5f45a88aacb6a 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tf +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json index 5ba9e7b6af80f..47f3624b64d70 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -68,16 +65,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -119,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -160,7 +154,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -183,7 +177,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -228,7 +222,7 @@ ] } }, - "timestamp": "2024-10-28T20:07:57Z", + "timestamp": "2025-03-04T19:25:10Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json index 875d8c9aaf439..6d23cab247b9d 100644 --- a/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json +++ b/provisioner/terraform/testdata/external-auth-providers/external-auth-providers.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -38,7 +38,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -54,19 +54,16 @@ } ], "env": null, - "id": "ec5d36c9-8690-4246-8ab3-2d85a3eacee6", + "id": "3af7f86b-3674-4e9d-b92d-d2e8890e5c38", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "78c55fa2-8e3c-4564-950d-e022c76cf05a", + "startup_script_behavior": "non-blocking", + "token": "cf973ff9-17e3-4e08-abc5-7a37d3f74d0f", "troubleshooting_url": null }, "sensitive_values": { @@ -85,7 +82,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "455343782636271645", + "id": "7283290279914631370", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfplan.json b/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfplan.json index fba34f1cb5f4d..adf7f32ffa4d6 100644 --- a/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfplan.json +++ b/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -119,7 +119,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -223,7 +223,7 @@ ] } }, - "timestamp": "2024-10-28T20:07:58Z", + "timestamp": "2025-03-04T19:25:12Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfstate.json b/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfstate.json index 3cf905c0a2948..5b7393c568a5a 100644 --- a/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfstate.json +++ b/provisioner/terraform/testdata/git-auth-providers/git-auth-providers.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -52,7 +52,7 @@ } ], "env": null, - "id": "ffa1f524-0350-4891-868d-93cad369318a", + "id": "1023a3a5-f8c1-45f6-a0cc-bf3a1e1f3c63", "init_script": "", "login_before_ready": true, "metadata": [], @@ -64,7 +64,7 @@ "startup_script": null, "startup_script_behavior": null, "startup_script_timeout": 300, - "token": "8ba649af-b498-4f20-8055-b6a0b995837e", + "token": "a59f2270-ac62-47bc-9c68-7bbfe2981c2e", "troubleshooting_url": null }, "sensitive_values": { @@ -83,7 +83,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7420557451345159984", + "id": "3284204005710492153", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tf b/provisioner/terraform/testdata/instance-id/instance-id.tf index 1cd4ab828b4f0..84e010a79d6e9 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tf +++ b/provisioner/terraform/testdata/instance-id/instance-id.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json b/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json index 527a2fa05769d..e287a5b6ab582 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "google-instance-identity", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -80,16 +77,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -156,7 +150,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -182,7 +176,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_agent_instance.main", @@ -225,7 +219,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:00Z", + "timestamp": "2025-03-04T19:25:13Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json index 929d72365502c..843ad66bc0a57 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "google-instance-identity", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "0389c8a5-cc5c-485d-959c-8738bada65ff", + "id": "9d3d75ba-4c12-42e5-bb49-62c258096d79", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "097b6128-8d60-4849-969b-03f0b463ac2c", + "startup_script_behavior": "non-blocking", + "token": "de14eb76-34b5-4da6-b40c-6c44aaeed2e1", "troubleshooting_url": null }, "sensitive_values": { @@ -57,8 +54,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { - "agent_id": "0389c8a5-cc5c-485d-959c-8738bada65ff", - "id": "0ae6bb98-871c-4091-8098-d32f256d8c05", + "agent_id": "9d3d75ba-4c12-42e5-bb49-62c258096d79", + "id": "2561b9a8-27a4-420f-aaf5-7b1641b2f7a6", "instance_id": "example" }, "sensitive_values": {}, @@ -74,7 +71,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5569763710827889183", + "id": "3284638190727292821", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/kubernetes-metadata/kubernetes-metadata.tf b/provisioner/terraform/testdata/kubernetes-metadata/kubernetes-metadata.tf index 2ae1298904fbb..faa08706de380 100644 --- a/provisioner/terraform/testdata/kubernetes-metadata/kubernetes-metadata.tf +++ b/provisioner/terraform/testdata/kubernetes-metadata/kubernetes-metadata.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } kubernetes = { source = "hashicorp/kubernetes" diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tf b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tf index 1e13495d6ebc7..7664ead2b4962 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tf +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json index 2151b4631647a..2fe0bf0425712 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -42,16 +39,16 @@ "name": "apps", "index": "app1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": "app1", "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -68,16 +65,16 @@ "name": "apps", "index": "app2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": "app2", "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": null, @@ -120,16 +117,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -164,10 +158,10 @@ "display_name": "app1", "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -201,10 +195,10 @@ "display_name": "app2", "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": null, @@ -248,7 +242,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -271,7 +265,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.apps", @@ -298,7 +292,7 @@ ] } }, - "schema_version": 0, + "schema_version": 1, "for_each_expression": { "references": [ "local.apps_map" @@ -327,7 +321,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:02Z", + "timestamp": "2025-03-04T19:25:15Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json index 9aaa7b352f518..1483341440ff5 100644 --- a/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json +++ b/provisioner/terraform/testdata/mapped-apps/mapped-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "b3d3e1d7-1f1f-4abf-8475-2058f73f3437", + "id": "0faf2a12-1797-43f9-8ad0-46e085d9810e", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "56420fd5-57e5-44e0-a264-53395b74505a", + "startup_script_behavior": "non-blocking", + "token": "5f5cf1c0-37d4-4809-a227-92bd64fcfb64", "troubleshooting_url": null }, "sensitive_values": { @@ -56,18 +53,18 @@ "name": "apps", "index": "app1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "b3d3e1d7-1f1f-4abf-8475-2058f73f3437", + "agent_id": "0faf2a12-1797-43f9-8ad0-46e085d9810e", "command": null, "display_name": "app1", "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "id": "e8163eb0-e56e-46e7-8848-8c6c250ce5b9", - "name": null, + "id": "ac8a8769-9b4d-4028-82b5-cce53b952fb8", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -87,18 +84,18 @@ "name": "apps", "index": "app2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "b3d3e1d7-1f1f-4abf-8475-2058f73f3437", + "agent_id": "0faf2a12-1797-43f9-8ad0-46e085d9810e", "command": null, "display_name": "app2", "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "id": "0971e625-7a23-4108-9765-78f7ad045b38", - "name": null, + "id": "403e8671-2ab1-4a16-b578-6436e4090844", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": null, @@ -119,7 +116,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "60927265551659604", + "id": "198476735862845239", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf index 02c6ff6c1b67f..8ac412b5b3894 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json index d8f5a4763518b..94b81267d85b6 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -41,23 +38,20 @@ "type": "coder_agent", "name": "dev2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -72,16 +66,16 @@ "type": "coder_app", "name": "app1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -97,7 +91,7 @@ "type": "coder_app", "name": "app2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": null, @@ -109,10 +103,10 @@ "url": "http://localhost:13337/healthz" } ], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": true, @@ -130,16 +124,16 @@ "type": "coder_app", "name": "app3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app3", "subdomain": false, @@ -194,16 +188,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -238,16 +229,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -281,10 +269,10 @@ "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -323,10 +311,10 @@ "url": "http://localhost:13337/healthz" } ], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": true, @@ -363,10 +351,10 @@ "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app3", "subdomain": false, @@ -431,7 +419,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -454,7 +442,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_agent.dev2", @@ -470,7 +458,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.app1", @@ -489,7 +477,7 @@ "constant_value": "app1" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.app2", @@ -524,7 +512,7 @@ "constant_value": true } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.app3", @@ -546,7 +534,7 @@ "constant_value": false } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev1", @@ -587,7 +575,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:05Z", + "timestamp": "2025-03-04T19:25:17Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json index 4a94e05baa29d..12ae6f84b2c08 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-apps/multiple-agents-multiple-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "571523c7-e7a3-420a-b65d-39d15f5f3267", + "id": "9cd3c7d2-75fb-4ad0-acba-40ae78434154", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "c18d762d-062d-43d4-b7c2-98be546b39a6", + "startup_script_behavior": "non-blocking", + "token": "fcf46094-a739-4acc-9d64-7b40b2fbdc5c", "troubleshooting_url": null }, "sensitive_values": { @@ -55,7 +52,7 @@ "type": "coder_agent", "name": "dev2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -71,19 +68,16 @@ } ], "env": null, - "id": "e94994f2-cab5-4288-8ff3-a290c95e4e25", + "id": "37b0b6fd-6f9e-4ad4-a273-6c4334d4bc02", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "c0757e3a-4be4-4643-b3ba-b27234169eb1", + "startup_script_behavior": "non-blocking", + "token": "ed7abd75-cdf7-4b4f-b092-3288cae29f80", "troubleshooting_url": null }, "sensitive_values": { @@ -100,18 +94,18 @@ "type": "coder_app", "name": "app1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "571523c7-e7a3-420a-b65d-39d15f5f3267", + "agent_id": "9cd3c7d2-75fb-4ad0-acba-40ae78434154", "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "id": "bf2b3c44-1b1d-49c5-9149-4f2f18590c60", - "name": null, + "id": "c267f275-9d8b-40da-a78b-cc3ad0cc4e94", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -130,9 +124,9 @@ "type": "coder_app", "name": "app2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "571523c7-e7a3-420a-b65d-39d15f5f3267", + "agent_id": "9cd3c7d2-75fb-4ad0-acba-40ae78434154", "command": null, "display_name": null, "external": false, @@ -143,11 +137,11 @@ "url": "http://localhost:13337/healthz" } ], + "hidden": false, "icon": null, - "id": "580cf864-a64d-4430-98b7-fa37c44083f8", - "name": null, + "id": "dd509891-e05b-4f3c-b860-bd240b4771f8", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": true, @@ -168,18 +162,18 @@ "type": "coder_app", "name": "app3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "e94994f2-cab5-4288-8ff3-a290c95e4e25", + "agent_id": "37b0b6fd-6f9e-4ad4-a273-6c4334d4bc02", "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "id": "182dca7b-12ab-4c58-9424-23b7d61135a9", - "name": null, + "id": "7b2bf8ad-c1ec-445d-acad-cfd046d6b950", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app3", "subdomain": false, @@ -200,7 +194,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3778543820798621894", + "id": "8605362455735888550", "triggers": null }, "sensitive_values": {}, @@ -216,7 +210,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "1094622314762410115", + "id": "2566554723161358367", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf index d167d44942776..e12a895d14baa 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json index 4cb28ae592516..96a20f87f89d9 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -41,23 +38,20 @@ "type": "coder_agent", "name": "dev2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -72,7 +66,7 @@ "type": "coder_env", "name": "env1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "name": "ENV_1", "value": "Env 1" @@ -85,7 +79,7 @@ "type": "coder_env", "name": "env2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "name": "ENV_2", "value": "Env 2" @@ -98,7 +92,7 @@ "type": "coder_env", "name": "env3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "name": "ENV_3", "value": "Env 3" @@ -150,16 +144,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -194,16 +185,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -338,7 +326,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -361,7 +349,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_agent.dev2", @@ -377,7 +365,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_env.env1", @@ -399,7 +387,7 @@ "constant_value": "Env 1" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_env.env2", @@ -421,7 +409,7 @@ "constant_value": "Env 2" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_env.env3", @@ -443,7 +431,7 @@ "constant_value": "Env 3" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev1", @@ -484,7 +472,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:06Z", + "timestamp": "2025-03-04T19:25:19Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json index f87b6f0a9eb56..64ed4878e2213 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-envs/multiple-agents-multiple-envs.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "702e7cd2-95a0-46cf-8ef7-c1dfbd3e56b9", + "id": "a1aa25b4-5c7d-44f6-95f8-2f32205f9625", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "1cfd79e3-3f9c-4d66-b7c2-42c385c26012", + "startup_script_behavior": "non-blocking", + "token": "274d380f-9d26-4cc4-8122-0591bef43b4e", "troubleshooting_url": null }, "sensitive_values": { @@ -55,7 +52,7 @@ "type": "coder_agent", "name": "dev2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -71,19 +68,16 @@ } ], "env": null, - "id": "ca137ba9-45ce-44ff-8e30-59a86565fa7d", + "id": "6e515c26-ca96-46ca-a220-83f17b2fcd95", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "0d3aa4f8-025c-4044-8053-d077484355fb", + "startup_script_behavior": "non-blocking", + "token": "794c95b3-3404-4f0e-a7a7-278f8bbfb5f0", "troubleshooting_url": null }, "sensitive_values": { @@ -100,10 +94,10 @@ "type": "coder_env", "name": "env1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "702e7cd2-95a0-46cf-8ef7-c1dfbd3e56b9", - "id": "e3d37294-2407-4286-a519-7551b901ba54", + "agent_id": "a1aa25b4-5c7d-44f6-95f8-2f32205f9625", + "id": "bce78af7-55f1-4868-8d1a-7aac6ea85090", "name": "ENV_1", "value": "Env 1" }, @@ -118,10 +112,10 @@ "type": "coder_env", "name": "env2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "702e7cd2-95a0-46cf-8ef7-c1dfbd3e56b9", - "id": "9451575b-da89-4297-a42d-4aaf0a23775d", + "agent_id": "a1aa25b4-5c7d-44f6-95f8-2f32205f9625", + "id": "33a6c102-c871-46ce-a78b-32c518d0b387", "name": "ENV_2", "value": "Env 2" }, @@ -136,10 +130,10 @@ "type": "coder_env", "name": "env3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "ca137ba9-45ce-44ff-8e30-59a86565fa7d", - "id": "948e3fb5-12a1-454b-b85e-d4dc1f01838f", + "agent_id": "6e515c26-ca96-46ca-a220-83f17b2fcd95", + "id": "3e746cf3-5a3f-446a-9643-4dffb344009c", "name": "ENV_3", "value": "Env 3" }, @@ -156,7 +150,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "7502424400840788651", + "id": "8646180706267246123", "triggers": null }, "sensitive_values": {}, @@ -172,7 +166,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "3916143681500058654", + "id": "3657189128073189353", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf new file mode 100644 index 0000000000000..f86ceb180edb5 --- /dev/null +++ b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tf @@ -0,0 +1,67 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "2.2.0-pre0" + } + } +} + +resource "coder_agent" "dev1" { + os = "linux" + arch = "amd64" + resources_monitoring { + memory { + enabled = true + threshold = 80 + } + } +} + +resource "coder_agent" "dev2" { + os = "linux" + arch = "amd64" + resources_monitoring { + memory { + enabled = true + threshold = 99 + } + volume { + path = "/volume1" + enabled = true + threshold = 80 + } + volume { + path = "/volume2" + enabled = false + threshold = 50 + } + } +} + +# app1 is for testing subdomain default. +resource "coder_app" "app1" { + agent_id = coder_agent.dev1.id + slug = "app1" + # subdomain should default to false. + # subdomain = false +} + +# app2 tests that subdomaincan be true, and that healthchecks work. +resource "coder_app" "app2" { + agent_id = coder_agent.dev1.id + slug = "app2" + subdomain = true + healthcheck { + url = "http://localhost:13337/healthz" + interval = 5 + threshold = 6 + } +} + +resource "null_resource" "dev" { + depends_on = [ + coder_agent.dev1, + coder_agent.dev2 + ] +} diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json new file mode 100644 index 0000000000000..5fb45060be911 --- /dev/null +++ b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfplan.json @@ -0,0 +1,625 @@ +{ + "format_version": "1.2", + "terraform_version": "1.10.5", + "planned_values": { + "root_module": { + "resources": [ + { + "address": "coder_agent.dev1", + "mode": "managed", + "type": "coder_agent", + "name": "dev1", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "env": null, + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [ + { + "memory": [ + { + "enabled": true, + "threshold": 80 + } + ], + "volume": [] + } + ], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "troubleshooting_url": null + }, + "sensitive_values": { + "display_apps": [], + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [] + } + ], + "token": true + } + }, + { + "address": "coder_agent.dev2", + "mode": "managed", + "type": "coder_agent", + "name": "dev2", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "env": null, + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [ + { + "memory": [ + { + "enabled": true, + "threshold": 99 + } + ], + "volume": [ + { + "enabled": false, + "path": "/volume2", + "threshold": 50 + }, + { + "enabled": true, + "path": "/volume1", + "threshold": 80 + } + ] + } + ], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "troubleshooting_url": null + }, + "sensitive_values": { + "display_apps": [], + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [ + {}, + {} + ] + } + ], + "token": true + } + }, + { + "address": "coder_app.app1", + "mode": "managed", + "type": "coder_app", + "name": "app1", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "command": null, + "display_name": null, + "external": false, + "healthcheck": [], + "hidden": false, + "icon": null, + "open_in": "slim-window", + "order": null, + "share": "owner", + "slug": "app1", + "subdomain": null, + "url": null + }, + "sensitive_values": { + "healthcheck": [] + } + }, + { + "address": "coder_app.app2", + "mode": "managed", + "type": "coder_app", + "name": "app2", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "command": null, + "display_name": null, + "external": false, + "healthcheck": [ + { + "interval": 5, + "threshold": 6, + "url": "http://localhost:13337/healthz" + } + ], + "hidden": false, + "icon": null, + "open_in": "slim-window", + "order": null, + "share": "owner", + "slug": "app2", + "subdomain": true, + "url": null + }, + "sensitive_values": { + "healthcheck": [ + {} + ] + } + }, + { + "address": "null_resource.dev", + "mode": "managed", + "type": "null_resource", + "name": "dev", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "triggers": null + }, + "sensitive_values": {} + } + ] + } + }, + "resource_changes": [ + { + "address": "coder_agent.dev1", + "mode": "managed", + "type": "coder_agent", + "name": "dev1", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "env": null, + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [ + { + "memory": [ + { + "enabled": true, + "threshold": 80 + } + ], + "volume": [] + } + ], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "troubleshooting_url": null + }, + "after_unknown": { + "display_apps": true, + "id": true, + "init_script": true, + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [] + } + ], + "token": true + }, + "before_sensitive": false, + "after_sensitive": { + "display_apps": [], + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [] + } + ], + "token": true + } + } + }, + { + "address": "coder_agent.dev2", + "mode": "managed", + "type": "coder_agent", + "name": "dev2", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "env": null, + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [ + { + "memory": [ + { + "enabled": true, + "threshold": 99 + } + ], + "volume": [ + { + "enabled": false, + "path": "/volume2", + "threshold": 50 + }, + { + "enabled": true, + "path": "/volume1", + "threshold": 80 + } + ] + } + ], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "troubleshooting_url": null + }, + "after_unknown": { + "display_apps": true, + "id": true, + "init_script": true, + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [ + {}, + {} + ] + } + ], + "token": true + }, + "before_sensitive": false, + "after_sensitive": { + "display_apps": [], + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [ + {}, + {} + ] + } + ], + "token": true + } + } + }, + { + "address": "coder_app.app1", + "mode": "managed", + "type": "coder_app", + "name": "app1", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "command": null, + "display_name": null, + "external": false, + "healthcheck": [], + "hidden": false, + "icon": null, + "open_in": "slim-window", + "order": null, + "share": "owner", + "slug": "app1", + "subdomain": null, + "url": null + }, + "after_unknown": { + "agent_id": true, + "healthcheck": [], + "id": true + }, + "before_sensitive": false, + "after_sensitive": { + "healthcheck": [] + } + } + }, + { + "address": "coder_app.app2", + "mode": "managed", + "type": "coder_app", + "name": "app2", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "command": null, + "display_name": null, + "external": false, + "healthcheck": [ + { + "interval": 5, + "threshold": 6, + "url": "http://localhost:13337/healthz" + } + ], + "hidden": false, + "icon": null, + "open_in": "slim-window", + "order": null, + "share": "owner", + "slug": "app2", + "subdomain": true, + "url": null + }, + "after_unknown": { + "agent_id": true, + "healthcheck": [ + {} + ], + "id": true + }, + "before_sensitive": false, + "after_sensitive": { + "healthcheck": [ + {} + ] + } + } + }, + { + "address": "null_resource.dev", + "mode": "managed", + "type": "null_resource", + "name": "dev", + "provider_name": "registry.terraform.io/hashicorp/null", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "triggers": null + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + } + ], + "configuration": { + "provider_config": { + "coder": { + "name": "coder", + "full_name": "registry.terraform.io/coder/coder", + "version_constraint": "2.2.0-pre0" + }, + "null": { + "name": "null", + "full_name": "registry.terraform.io/hashicorp/null" + } + }, + "root_module": { + "resources": [ + { + "address": "coder_agent.dev1", + "mode": "managed", + "type": "coder_agent", + "name": "dev1", + "provider_config_key": "coder", + "expressions": { + "arch": { + "constant_value": "amd64" + }, + "os": { + "constant_value": "linux" + }, + "resources_monitoring": [ + { + "memory": [ + { + "enabled": { + "constant_value": true + }, + "threshold": { + "constant_value": 80 + } + } + ] + } + ] + }, + "schema_version": 1 + }, + { + "address": "coder_agent.dev2", + "mode": "managed", + "type": "coder_agent", + "name": "dev2", + "provider_config_key": "coder", + "expressions": { + "arch": { + "constant_value": "amd64" + }, + "os": { + "constant_value": "linux" + }, + "resources_monitoring": [ + { + "memory": [ + { + "enabled": { + "constant_value": true + }, + "threshold": { + "constant_value": 99 + } + } + ], + "volume": [ + { + "enabled": { + "constant_value": true + }, + "path": { + "constant_value": "/volume1" + }, + "threshold": { + "constant_value": 80 + } + }, + { + "enabled": { + "constant_value": false + }, + "path": { + "constant_value": "/volume2" + }, + "threshold": { + "constant_value": 50 + } + } + ] + } + ] + }, + "schema_version": 1 + }, + { + "address": "coder_app.app1", + "mode": "managed", + "type": "coder_app", + "name": "app1", + "provider_config_key": "coder", + "expressions": { + "agent_id": { + "references": [ + "coder_agent.dev1.id", + "coder_agent.dev1" + ] + }, + "slug": { + "constant_value": "app1" + } + }, + "schema_version": 1 + }, + { + "address": "coder_app.app2", + "mode": "managed", + "type": "coder_app", + "name": "app2", + "provider_config_key": "coder", + "expressions": { + "agent_id": { + "references": [ + "coder_agent.dev1.id", + "coder_agent.dev1" + ] + }, + "healthcheck": [ + { + "interval": { + "constant_value": 5 + }, + "threshold": { + "constant_value": 6 + }, + "url": { + "constant_value": "http://localhost:13337/healthz" + } + } + ], + "slug": { + "constant_value": "app2" + }, + "subdomain": { + "constant_value": true + } + }, + "schema_version": 1 + }, + { + "address": "null_resource.dev", + "mode": "managed", + "type": "null_resource", + "name": "dev", + "provider_config_key": "null", + "schema_version": 0, + "depends_on": [ + "coder_agent.dev1", + "coder_agent.dev2" + ] + } + ] + } + }, + "relevant_attributes": [ + { + "resource": "coder_agent.dev1", + "attribute": [ + "id" + ] + } + ], + "timestamp": "2025-03-04T19:25:21Z", + "applyable": true, + "complete": true, + "errored": false +} diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json new file mode 100644 index 0000000000000..fa19d308dff44 --- /dev/null +++ b/provisioner/terraform/testdata/multiple-agents-multiple-monitors/multiple-agents-multiple-monitors.tfstate.json @@ -0,0 +1,231 @@ +{ + "format_version": "1.0", + "terraform_version": "1.10.5", + "values": { + "root_module": { + "resources": [ + { + "address": "coder_agent.dev1", + "mode": "managed", + "type": "coder_agent", + "name": "dev1", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "display_apps": [ + { + "port_forwarding_helper": true, + "ssh_helper": true, + "vscode": true, + "vscode_insiders": false, + "web_terminal": true + } + ], + "env": null, + "id": "baa57f58-60fb-4490-9f11-1f7e17ae698a", + "init_script": "", + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [ + { + "memory": [ + { + "enabled": true, + "threshold": 80 + } + ], + "volume": [] + } + ], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "token": "6a54f7c6-93b5-4d2f-a194-7b6f968b9293", + "troubleshooting_url": null + }, + "sensitive_values": { + "display_apps": [ + {} + ], + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [] + } + ], + "token": true + } + }, + { + "address": "coder_agent.dev2", + "mode": "managed", + "type": "coder_agent", + "name": "dev2", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "arch": "amd64", + "auth": "token", + "connection_timeout": 120, + "dir": null, + "display_apps": [ + { + "port_forwarding_helper": true, + "ssh_helper": true, + "vscode": true, + "vscode_insiders": false, + "web_terminal": true + } + ], + "env": null, + "id": "60fa4e03-a7b1-47fc-9977-7cf43bb04f1f", + "init_script": "", + "metadata": [], + "motd_file": null, + "order": null, + "os": "linux", + "resources_monitoring": [ + { + "memory": [ + { + "enabled": true, + "threshold": 99 + } + ], + "volume": [ + { + "enabled": false, + "path": "/volume2", + "threshold": 50 + }, + { + "enabled": true, + "path": "/volume1", + "threshold": 80 + } + ] + } + ], + "shutdown_script": null, + "startup_script": null, + "startup_script_behavior": "non-blocking", + "token": "753eb1c8-e032-4d9c-baea-4534040f68d9", + "troubleshooting_url": null + }, + "sensitive_values": { + "display_apps": [ + {} + ], + "metadata": [], + "resources_monitoring": [ + { + "memory": [ + {} + ], + "volume": [ + {}, + {} + ] + } + ], + "token": true + } + }, + { + "address": "coder_app.app1", + "mode": "managed", + "type": "coder_app", + "name": "app1", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "agent_id": "baa57f58-60fb-4490-9f11-1f7e17ae698a", + "command": null, + "display_name": null, + "external": false, + "healthcheck": [], + "hidden": false, + "icon": null, + "id": "9e46f6e5-72c3-4502-b0f8-36bcec12baba", + "open_in": "slim-window", + "order": null, + "share": "owner", + "slug": "app1", + "subdomain": null, + "url": null + }, + "sensitive_values": { + "healthcheck": [] + }, + "depends_on": [ + "coder_agent.dev1" + ] + }, + { + "address": "coder_app.app2", + "mode": "managed", + "type": "coder_app", + "name": "app2", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 1, + "values": { + "agent_id": "baa57f58-60fb-4490-9f11-1f7e17ae698a", + "command": null, + "display_name": null, + "external": false, + "healthcheck": [ + { + "interval": 5, + "threshold": 6, + "url": "http://localhost:13337/healthz" + } + ], + "hidden": false, + "icon": null, + "id": "e3591c31-401b-44c6-bbba-df36d02199c8", + "open_in": "slim-window", + "order": null, + "share": "owner", + "slug": "app2", + "subdomain": true, + "url": null + }, + "sensitive_values": { + "healthcheck": [ + {} + ] + }, + "depends_on": [ + "coder_agent.dev1" + ] + }, + { + "address": "null_resource.dev", + "mode": "managed", + "type": "null_resource", + "name": "dev", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "id": "4101480329869104281", + "triggers": null + }, + "sensitive_values": {}, + "depends_on": [ + "coder_agent.dev1", + "coder_agent.dev2" + ] + } + ] + } + } +} diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf index af041e2da350d..c0aee0d2d97e5 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json index ab14e49f02989..8a6311e03958b 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -41,23 +38,20 @@ "type": "coder_agent", "name": "dev2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -72,7 +66,7 @@ "type": "coder_script", "name": "script1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "cron": null, "display_name": "Foobar Script 1", @@ -92,7 +86,7 @@ "type": "coder_script", "name": "script2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "cron": null, "display_name": "Foobar Script 2", @@ -112,7 +106,7 @@ "type": "coder_script", "name": "script3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "cron": null, "display_name": "Foobar Script 3", @@ -171,16 +165,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -215,16 +206,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -380,7 +368,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -403,7 +391,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_agent.dev2", @@ -419,7 +407,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_script.script1", @@ -444,7 +432,7 @@ "constant_value": "echo foobar 1" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_script.script2", @@ -469,7 +457,7 @@ "constant_value": "echo foobar 2" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_script.script3", @@ -494,7 +482,7 @@ "constant_value": "echo foobar 3" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev1", @@ -523,19 +511,19 @@ }, "relevant_attributes": [ { - "resource": "coder_agent.dev1", + "resource": "coder_agent.dev2", "attribute": [ "id" ] }, { - "resource": "coder_agent.dev2", + "resource": "coder_agent.dev1", "attribute": [ "id" ] } ], - "timestamp": "2024-10-28T20:08:08Z", + "timestamp": "2025-03-04T19:25:23Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json index 37c4ef13ee6fb..26c719f7d730a 100644 --- a/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents-multiple-scripts/multiple-agents-multiple-scripts.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "753eb8c0-e2b7-4cbc-b0ff-1370ce2e4022", + "id": "0ae6e69a-d5ca-4b40-9a79-67e11b317742", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "77b179b6-0e2d-4307-9ba0-98325fc96e37", + "startup_script_behavior": "non-blocking", + "token": "0a20b766-43d1-4074-a445-384257e5de27", "troubleshooting_url": null }, "sensitive_values": { @@ -55,7 +52,7 @@ "type": "coder_agent", "name": "dev2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -71,19 +68,16 @@ } ], "env": null, - "id": "86f7e422-1798-4de5-8209-69b023808241", + "id": "622c6b37-cea1-4f6d-9f01-55e5cdd541a6", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "aa4ae02d-4084-4dff-951c-af10f78a98c2", + "startup_script_behavior": "non-blocking", + "token": "055f173e-755a-4829-b817-1d5ccf054f70", "troubleshooting_url": null }, "sensitive_values": { @@ -100,13 +94,13 @@ "type": "coder_script", "name": "script1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "753eb8c0-e2b7-4cbc-b0ff-1370ce2e4022", + "agent_id": "0ae6e69a-d5ca-4b40-9a79-67e11b317742", "cron": null, "display_name": "Foobar Script 1", "icon": null, - "id": "eb1eb8f4-3a4a-4040-bd6a-0abce01d6330", + "id": "34f6c49b-8c99-4bd1-a40f-24ee011fb490", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -125,13 +119,13 @@ "type": "coder_script", "name": "script2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "753eb8c0-e2b7-4cbc-b0ff-1370ce2e4022", + "agent_id": "0ae6e69a-d5ca-4b40-9a79-67e11b317742", "cron": null, "display_name": "Foobar Script 2", "icon": null, - "id": "1de43abc-8416-4455-87ca-23fb425b4eeb", + "id": "4c6bc57b-23fc-41c2-86c5-4f3a899e171c", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -150,13 +144,13 @@ "type": "coder_script", "name": "script3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "86f7e422-1798-4de5-8209-69b023808241", + "agent_id": "622c6b37-cea1-4f6d-9f01-55e5cdd541a6", "cron": null, "display_name": "Foobar Script 3", "icon": null, - "id": "ede835f7-4018-464c-807d-7e07af7de9d3", + "id": "8ff5a1e9-ca8c-442f-89c2-dd7e2d8e74d7", "log_path": null, "run_on_start": true, "run_on_stop": false, @@ -177,7 +171,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4207133259459553257", + "id": "7783428659239328742", "triggers": null }, "sensitive_values": {}, @@ -193,7 +187,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5647997484430231619", + "id": "8319259774862919105", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json index 67da167932aa4..2ce46aa6dabff 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -464,7 +464,7 @@ ] } }, - "timestamp": "2024-10-28T20:08:03Z", + "timestamp": "2025-03-04T19:25:25Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json index cd8edc0ae29bc..fbdf9416a3e88 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -26,7 +26,7 @@ } ], "env": null, - "id": "c76ed902-d4cb-4905-9961-4d58dda135f9", + "id": "996be323-1195-4cee-9d00-778a025fbaf9", "init_script": "", "login_before_ready": true, "metadata": [], @@ -38,7 +38,7 @@ "startup_script": null, "startup_script_behavior": null, "startup_script_timeout": 300, - "token": "f1aa99ea-570d-49cf-aef9-a4241e3cb023", + "token": "df89f5a4-3349-40eb-a628-d20f5e8ffb93", "troubleshooting_url": null }, "sensitive_values": { @@ -71,7 +71,7 @@ } ], "env": null, - "id": "1b037439-4eb3-408e-83da-28dc93645944", + "id": "8c9bbbf8-0049-47d6-afef-555f2e4c8f31", "init_script": "", "login_before_ready": true, "metadata": [], @@ -83,7 +83,7 @@ "startup_script": null, "startup_script_behavior": "non-blocking", "startup_script_timeout": 30, - "token": "20d4e89e-d6de-4eb7-8877-f9186d684aa5", + "token": "26d616b2-9df3-43b2-b89b-dc8665dbcff4", "troubleshooting_url": null }, "sensitive_values": { @@ -116,7 +116,7 @@ } ], "env": null, - "id": "453b5404-8ea4-4197-8664-3638e6a012ca", + "id": "33ed3e88-edf5-4bc8-a0bb-1f743ffb169d", "init_script": "", "login_before_ready": true, "metadata": [], @@ -128,7 +128,7 @@ "startup_script": null, "startup_script_behavior": "blocking", "startup_script_timeout": 300, - "token": "0355cb42-9da0-4bad-b2aa-74db1df76fef", + "token": "42292f6c-6fc4-43f4-8de9-219990cc4a93", "troubleshooting_url": "https://coder.com/troubleshoot" }, "sensitive_values": { @@ -161,7 +161,7 @@ } ], "env": null, - "id": "c0a68e9b-5b29-4d95-b664-5ac71dd633cf", + "id": "f1ff7240-3700-494d-a0fd-6a88459d8ab7", "init_script": "", "login_before_ready": false, "metadata": [], @@ -173,7 +173,7 @@ "startup_script": null, "startup_script_behavior": null, "startup_script_timeout": 300, - "token": "34b78439-5d6e-431b-b06c-339f97a1e9cf", + "token": "2d133297-d1b2-486e-8b3e-078df4ed0de7", "troubleshooting_url": null }, "sensitive_values": { @@ -192,7 +192,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5109814714394194897", + "id": "1432868857711807382", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tf b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tf index c7c4f9968b5c3..c52f4a58b36f4 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tf +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json index b156c3b5068b6..c0c11ddf7cde7 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -41,16 +38,16 @@ "type": "coder_app", "name": "app1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -66,7 +63,7 @@ "type": "coder_app", "name": "app2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": null, @@ -78,10 +75,10 @@ "url": "http://localhost:13337/healthz" } ], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": true, @@ -99,16 +96,16 @@ "type": "coder_app", "name": "app3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app3", "subdomain": false, @@ -151,16 +148,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -194,10 +188,10 @@ "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -236,10 +230,10 @@ "url": "http://localhost:13337/healthz" } ], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": true, @@ -276,10 +270,10 @@ "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "name": null, + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app3", "subdomain": false, @@ -323,7 +317,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -346,7 +340,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.app1", @@ -365,7 +359,7 @@ "constant_value": "app1" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.app2", @@ -400,7 +394,7 @@ "constant_value": true } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_app.app3", @@ -422,7 +416,7 @@ "constant_value": false } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -446,7 +440,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:10Z", + "timestamp": "2025-03-04T19:25:27Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json index d3fc254bf40b0..d0c33353e4e18 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "dev1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,19 +26,16 @@ } ], "env": null, - "id": "b3ea3cb0-176c-4642-9bf5-cfa72e0782cc", + "id": "d71e5147-0345-4be6-aa12-a90ca441db12", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "30533677-f04a-493b-b6cb-314d9abf7769", + "startup_script_behavior": "non-blocking", + "token": "3a74d687-a18c-4988-9d65-6659577553dd", "troubleshooting_url": null }, "sensitive_values": { @@ -55,18 +52,18 @@ "type": "coder_app", "name": "app1", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "b3ea3cb0-176c-4642-9bf5-cfa72e0782cc", + "agent_id": "d71e5147-0345-4be6-aa12-a90ca441db12", "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "id": "537e9069-492b-4721-96dd-cffba275ecd9", - "name": null, + "id": "3d1b6545-ab67-458d-abb1-7a7f3ef2c8a6", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app1", "subdomain": null, @@ -85,9 +82,9 @@ "type": "coder_app", "name": "app2", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "b3ea3cb0-176c-4642-9bf5-cfa72e0782cc", + "agent_id": "d71e5147-0345-4be6-aa12-a90ca441db12", "command": null, "display_name": null, "external": false, @@ -98,11 +95,11 @@ "url": "http://localhost:13337/healthz" } ], + "hidden": false, "icon": null, - "id": "3a4c78a0-7ea3-44aa-9ea8-4e08e387b4b6", - "name": null, + "id": "0ec8ec9c-67b2-4e1a-8f18-346bda58a06f", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app2", "subdomain": true, @@ -123,18 +120,18 @@ "type": "coder_app", "name": "app3", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { - "agent_id": "b3ea3cb0-176c-4642-9bf5-cfa72e0782cc", + "agent_id": "d71e5147-0345-4be6-aa12-a90ca441db12", "command": null, "display_name": null, "external": false, "healthcheck": [], + "hidden": false, "icon": null, - "id": "23555681-0ecb-4962-8e85-367d3a9d0228", - "name": null, + "id": "97559bb9-cf0f-4b83-9e53-25cd7c785f34", + "open_in": "slim-window", "order": null, - "relative_path": null, "share": "owner", "slug": "app3", "subdomain": false, @@ -155,7 +152,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2905101599123333983", + "id": "8869597861449516263", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tf b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tf index b316db7c3cdf1..b88a672f0047a 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tf +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json index 3b7881701038c..04f3fe1056037 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,14 +10,13 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [ { "display_name": "Process Count", @@ -32,10 +31,8 @@ "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -52,7 +49,7 @@ "type": "coder_metadata", "name": "about_info", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "daily_cost": 29, "hide": true, @@ -83,7 +80,7 @@ "type": "coder_metadata", "name": "other_info", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "daily_cost": 20, "hide": true, @@ -135,7 +132,6 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [ { "display_name": "Process Count", @@ -150,10 +146,8 @@ "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -291,7 +285,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -333,7 +327,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_metadata.about_info", @@ -373,7 +367,7 @@ ] } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_metadata.other_info", @@ -408,7 +402,7 @@ ] } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.about", @@ -432,7 +426,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:13Z", + "timestamp": "2025-03-04T19:25:29Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json index 170630d0e3103..a13acd6b519b2 100644 --- a/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json +++ b/provisioner/terraform/testdata/resource-metadata-duplicate/resource-metadata-duplicate.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,9 +26,8 @@ } ], "env": null, - "id": "0cbc2449-fbaa-447a-8487-6c47367af0be", + "id": "3d4f1a36-68cd-4c91-92dd-d07ccb515553", "init_script": "", - "login_before_ready": true, "metadata": [ { "display_name": "Process Count", @@ -43,11 +42,9 @@ "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "b03606cc-1ed3-4187-964d-389cf2ef223f", + "startup_script_behavior": "non-blocking", + "token": "95c49419-c343-4185-9132-4f7b64105e6c", "troubleshooting_url": null }, "sensitive_values": { @@ -66,12 +63,12 @@ "type": "coder_metadata", "name": "about_info", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "daily_cost": 29, "hide": true, "icon": "/icon/server.svg", - "id": "d6c33b98-addd-4d97-8659-405350bc06c1", + "id": "49d732e1-2d98-457d-84f2-088660d6e80b", "item": [ { "is_null": false, @@ -86,7 +83,7 @@ "value": "" } ], - "resource_id": "5673227143105805783" + "resource_id": "771326507239132201" }, "sensitive_values": { "item": [ @@ -105,12 +102,12 @@ "type": "coder_metadata", "name": "other_info", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "daily_cost": 20, "hide": true, "icon": "/icon/server.svg", - "id": "76594f08-2261-4114-a61f-e07107a86f89", + "id": "a2a626bc-7e5b-48cb-919b-449f40d7b145", "item": [ { "is_null": false, @@ -119,7 +116,7 @@ "value": "world" } ], - "resource_id": "5673227143105805783" + "resource_id": "771326507239132201" }, "sensitive_values": { "item": [ @@ -139,7 +136,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "5673227143105805783", + "id": "771326507239132201", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tf b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tf index cd46057ce8526..eb9f2eff89877 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tf +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json index f9c24830c6ef3..05d87f4fc7c4b 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,14 +10,13 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [ { "display_name": "Process Count", @@ -32,10 +31,8 @@ "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -52,7 +49,7 @@ "type": "coder_metadata", "name": "about_info", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "daily_cost": 29, "hide": true, @@ -122,7 +119,6 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [ { "display_name": "Process Count", @@ -137,10 +133,8 @@ "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -256,7 +250,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -301,7 +295,7 @@ "constant_value": "linux" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "coder_metadata.about_info", @@ -360,7 +354,7 @@ ] } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.about", @@ -384,7 +378,7 @@ ] } ], - "timestamp": "2024-10-28T20:08:11Z", + "timestamp": "2025-03-04T19:25:30Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json index a41aff216b11c..a2b1be2257a3f 100644 --- a/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json +++ b/provisioner/terraform/testdata/resource-metadata/resource-metadata.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -10,7 +10,7 @@ "type": "coder_agent", "name": "main", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "amd64", "auth": "token", @@ -26,9 +26,8 @@ } ], "env": null, - "id": "3bcbc547-b434-4dbd-b5ed-551edfba1b5c", + "id": "e7fbb3ac-d754-44b5-aa2b-bef6b9f358ff", "init_script": "", - "login_before_ready": true, "metadata": [ { "display_name": "Process Count", @@ -43,11 +42,9 @@ "order": null, "os": "linux", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "2d25fcc3-a355-4e92-98c6-ab780894ffee", + "startup_script_behavior": "non-blocking", + "token": "e82b787b-e97e-4555-8680-cf6a887dfc6a", "troubleshooting_url": null }, "sensitive_values": { @@ -66,12 +63,12 @@ "type": "coder_metadata", "name": "about_info", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "daily_cost": 29, "hide": true, "icon": "/icon/server.svg", - "id": "d9ce721c-dff3-44fd-92d1-155f37c84a56", + "id": "4eed85bc-cefc-487a-b7f4-ef39ada0d3e0", "item": [ { "is_null": false, @@ -98,7 +95,7 @@ "value": "squirrel" } ], - "resource_id": "4099397325680267994" + "resource_id": "4279195833018001043" }, "sensitive_values": { "item": [ @@ -121,7 +118,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4099397325680267994", + "id": "4279195833018001043", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tf b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tf index 82e7a6f95694e..fc684a6e583ee 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tf +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json index 72120dfaabeec..58e3d054bba5b 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "arm64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -68,16 +65,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -119,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -136,7 +130,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "e8805d7c-1636-4416-9520-b83234d68ddc", + "id": "965c2bc9-936f-43d5-9287-36603538790a", "mutable": false, "name": "Example", "option": null, @@ -163,7 +157,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "df43829a-49ce-4911-97ef-2fca78456c9f", + "id": "6472f1a0-e75c-45a2-9a49-0bb7adcb3e23", "mutable": false, "name": "Sample", "option": null, @@ -186,7 +180,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -209,7 +203,7 @@ "constant_value": "windows" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -269,7 +263,7 @@ ] } }, - "timestamp": "2024-10-28T20:08:17Z", + "timestamp": "2025-03-04T19:25:32Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json index 1d675d685a37c..c2a3fda518070 100644 --- a/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters-order/rich-parameters-order.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "81ada233-3a30-49d3-a56f-aca92f19c411", + "id": "03899941-4e7d-4e74-bcfb-92dc9619a85d", "mutable": false, "name": "Example", "option": null, @@ -44,7 +44,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "4dc1049f-0d54-408a-a412-95629ae5cd84", + "id": "632aa89d-d903-44c3-b44c-eb131498c579", "mutable": false, "name": "Sample", "option": null, @@ -64,7 +64,7 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "arm64", "auth": "token", @@ -80,19 +80,16 @@ } ], "env": null, - "id": "86cc4d6e-23b3-4632-9bc9-d3a321e8b906", + "id": "f67efb88-ae6d-4f33-8065-50b420c1ce80", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "0c3e7639-bafc-4e62-8e38-cb4e1b44e3f3", + "startup_script_behavior": "non-blocking", + "token": "164cba1c-98ce-4590-8ebb-f966a66a2301", "troubleshooting_url": null }, "sensitive_values": { @@ -111,7 +108,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2501594036325466407", + "id": "2247834665085956471", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tf b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tf index c05e8d5d4ae32..8067c0fa9337c 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tf +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json index 66153605ee4a0..bd103658ad3d7 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "arm64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -68,16 +65,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -119,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -136,7 +130,7 @@ "display_name": null, "ephemeral": true, "icon": null, - "id": "df8ad066-047d-434d-baa3-e19517ee7395", + "id": "fd220d2f-a3e7-4f6b-9870-ebe0ccb3e5c9", "mutable": true, "name": "number_example", "option": null, @@ -163,7 +157,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "7d9658aa-ff69-477a-9063-e9fd49fd9a9b", + "id": "b8288523-b649-48d0-928c-ae99069adda2", "mutable": false, "name": "number_example_max", "option": null, @@ -202,7 +196,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "bd6fcaac-db7f-4c4d-a664-fe7f47fad28a", + "id": "07c9e8e7-3dd2-4674-875b-ac6369cf5420", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -241,7 +235,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "8d42942d-5a10-43c9-a31d-d3fe9a7814e8", + "id": "b8f0a3fc-277d-47b2-a7a2-1267430b8cd8", "mutable": false, "name": "number_example_min", "option": null, @@ -280,7 +274,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "695301d0-8325-4685-824d-1ca9591689e3", + "id": "260e9363-5c18-4e22-a1e2-9a28f0a0d14a", "mutable": false, "name": "number_example_min_max", "option": null, @@ -319,7 +313,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "cd921934-d1b1-4370-8a73-2d43658ea877", + "id": "79a04ae2-4098-4482-a83b-2de95174ff22", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -354,7 +348,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "null": { "name": "null", @@ -377,7 +371,7 @@ "constant_value": "windows" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -551,7 +545,7 @@ ] } }, - "timestamp": "2024-10-28T20:08:18Z", + "timestamp": "2025-03-04T19:25:34Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json index 35b981c3a9b54..1ba6a2b297eb0 100644 --- a/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters-validation/rich-parameters-validation.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": true, "icon": null, - "id": "e09e9110-2f11-4a45-bc9f-dc7a12834ef0", + "id": "9f9ddc8e-bd35-4fa9-ade3-8f206c96d2e8", "mutable": true, "name": "number_example", "option": null, @@ -44,7 +44,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "7ba6324d-d8fd-43b8-91d2-d970a424db8b", + "id": "1a989e82-d7a9-460f-9d0d-fd3adcbf0aeb", "mutable": false, "name": "number_example_max", "option": null, @@ -83,7 +83,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "64e12007-8479-43bf-956b-86fe7ae73066", + "id": "ded0470e-2a18-4509-a675-adba973eb034", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -122,7 +122,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "32681b2b-682f-4a5f-9aa6-c05be9d41a89", + "id": "1fd9df82-d747-4a35-a717-87e867efff71", "mutable": false, "name": "number_example_min", "option": null, @@ -161,7 +161,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "03b67b89-0d35-449d-8997-f5ce4b7c1518", + "id": "22450c89-855a-43ff-9757-0516c72ab437", "mutable": false, "name": "number_example_min_max", "option": null, @@ -200,7 +200,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "2201fc53-38c6-4a68-b3b9-4f6ef3390962", + "id": "32ffe953-8cf6-4637-bf00-171012629ea5", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -232,7 +232,7 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "arm64", "auth": "token", @@ -248,19 +248,16 @@ } ], "env": null, - "id": "060ffd05-39a9-4fa3-81a3-7d9d8e655bf8", + "id": "d930846f-c291-4d31-8f5e-7f1080831b38", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "58ed35b2-6124-4183-a493-40cb0174f4d2", + "startup_script_behavior": "non-blocking", + "token": "03f35d2f-6476-407f-9ac8-bbe0892b5de8", "troubleshooting_url": null }, "sensitive_values": { @@ -279,7 +276,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4610812354433374355", + "id": "6098797437627753082", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/rich-parameters/external-module/child-external-module/main.tf b/provisioner/terraform/testdata/rich-parameters/external-module/child-external-module/main.tf index ac6f4c621a9d0..e8afbbf917fb5 100644 --- a/provisioner/terraform/testdata/rich-parameters/external-module/child-external-module/main.tf +++ b/provisioner/terraform/testdata/rich-parameters/external-module/child-external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/rich-parameters/external-module/main.tf b/provisioner/terraform/testdata/rich-parameters/external-module/main.tf index 55e942ec24e1f..0cf81d0162d07 100644 --- a/provisioner/terraform/testdata/rich-parameters/external-module/main.tf +++ b/provisioner/terraform/testdata/rich-parameters/external-module/main.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } docker = { source = "kreuzwerker/docker" diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tf b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tf index fc85769c8e9cc..24582eac30a5d 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tf +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tf @@ -2,7 +2,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = "0.22.0" + version = ">=2.0.0" } } } diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json index 1ec2927a40ad1..63cb47bb25279 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfplan.json @@ -1,6 +1,6 @@ { "format_version": "1.2", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "planned_values": { "root_module": { "resources": [ @@ -10,23 +10,20 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "arm64", "auth": "token", "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "sensitive_values": { @@ -68,16 +65,13 @@ "connection_timeout": 120, "dir": null, "env": null, - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, + "startup_script_behavior": "non-blocking", "troubleshooting_url": null }, "after_unknown": { @@ -119,7 +113,7 @@ ], "prior_state": { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -136,7 +130,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "cbec5bff-b81a-4815-99c0-40c0629779fb", + "id": "d15a5f2d-00a6-4d44-ba1d-340c4172e882", "mutable": false, "name": "Example", "option": [ @@ -180,7 +174,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "dd1c36b7-a961-4eb2-9687-c32b5ee54fbc", + "id": "fbdc4337-1adc-4ec7-8157-5065a4523356", "mutable": false, "name": "number_example", "option": null, @@ -207,7 +201,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "f1bcac54-a58c-44b2-94f5-243a0b1492d3", + "id": "e0555e6b-3899-4c51-a755-398e7369314f", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -246,7 +240,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "79c76ac1-8e71-4872-9107-d7a9529f7dce", + "id": "718dc4d2-62ac-4ca0-b303-16d511e0a0e8", "mutable": false, "name": "number_example_min_max", "option": null, @@ -285,7 +279,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "da7a8aff-ffe3-402f-bf7e-b369ae04b041", + "id": "3d4d7d00-698b-46f7-904d-acfd84c7822a", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -324,7 +318,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "5fe2dad0-e11f-46f0-80ae-c0c3a29cd1fd", + "id": "587f613d-2ec6-4cb7-8e9c-b61ca12ac9ca", "mutable": false, "name": "Sample", "option": null, @@ -355,7 +349,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "920f98a1-3a6f-4602-8c87-ebbbef0310c5", + "id": "a7f7ce22-ea95-45f9-80fa-774afd033d40", "mutable": true, "name": "First parameter from module", "option": null, @@ -382,7 +376,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "f438d9ad-6c3e-44f3-95cd-1d423a9b09e5", + "id": "86f108c2-91f1-4347-b667-e0afee5fa666", "mutable": true, "name": "Second parameter from module", "option": null, @@ -414,7 +408,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "b2c53701-be53-4591-aacf-1c83f75bcf15", + "id": "f3c13a53-aebd-4a78-81a4-ad75874f2238", "mutable": true, "name": "First parameter from child module", "option": null, @@ -441,7 +435,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "038b18d4-d430-4703-886a-b7e10e01f856", + "id": "7c8a6913-382c-4874-87a9-76fac542f6e0", "mutable": true, "name": "Second parameter from child module", "option": null, @@ -469,7 +463,7 @@ "coder": { "name": "coder", "full_name": "registry.terraform.io/coder/coder", - "version_constraint": "0.22.0" + "version_constraint": ">= 2.0.0" }, "module.this_is_external_module:docker": { "name": "docker", @@ -498,7 +492,7 @@ "constant_value": "windows" } }, - "schema_version": 0 + "schema_version": 1 }, { "address": "null_resource.dev", @@ -794,7 +788,7 @@ } } }, - "timestamp": "2024-10-28T20:08:15Z", + "timestamp": "2025-03-04T19:25:36Z", "applyable": true, "complete": true, "errored": false diff --git a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json index 1bfc1835dfcaf..60dec620c89a5 100644 --- a/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json +++ b/provisioner/terraform/testdata/rich-parameters/rich-parameters.tfstate.json @@ -1,6 +1,6 @@ { "format_version": "1.0", - "terraform_version": "1.9.8", + "terraform_version": "1.10.5", "values": { "root_module": { "resources": [ @@ -17,7 +17,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "8586d419-7e61-4e67-b8df-d98d8ac7ffd3", + "id": "5b27dba2-e9b1-408f-b8af-0ce18692c189", "mutable": false, "name": "Example", "option": [ @@ -61,7 +61,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "0cc54450-13a6-486c-b542-6e23a9f3596b", + "id": "5b357564-7fbb-4d32-9775-b0f0e8ec201a", "mutable": false, "name": "number_example", "option": null, @@ -88,7 +88,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "0c0b913a-0bde-4b9e-8a70-06d9b6d38a26", + "id": "41994818-572f-482d-a565-ce260ca414fc", "mutable": false, "name": "number_example_max_zero", "option": null, @@ -127,7 +127,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "37fd5372-2741-49dd-bf01-6ba29a24c9dd", + "id": "72683cb2-279f-4c59-a598-7d88da6b9cb7", "mutable": false, "name": "number_example_min_max", "option": null, @@ -166,7 +166,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "c0fd84ff-117f-442a-95f7-e8368ba7ce1d", + "id": "d5c94b27-982b-4d4f-a1c0-1f59a2b50f92", "mutable": false, "name": "number_example_min_zero", "option": null, @@ -205,7 +205,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "ab067ffc-99de-4705-97fe-16c713d2d115", + "id": "27867d73-1f2d-407b-bbc9-9dc612d1a0a7", "mutable": false, "name": "Sample", "option": null, @@ -225,7 +225,7 @@ "type": "coder_agent", "name": "dev", "provider_name": "registry.terraform.io/coder/coder", - "schema_version": 0, + "schema_version": 1, "values": { "arch": "arm64", "auth": "token", @@ -241,19 +241,16 @@ } ], "env": null, - "id": "7daab302-d00e-48d4-878c-47afbe3a13bc", + "id": "e8c8b049-5c00-421f-8a86-a608ddd35d0d", "init_script": "", - "login_before_ready": true, "metadata": [], "motd_file": null, "order": null, "os": "windows", "shutdown_script": null, - "shutdown_script_timeout": 300, "startup_script": null, - "startup_script_behavior": null, - "startup_script_timeout": 300, - "token": "e98c452d-cbe9-4ae1-8382-a986089dccb4", + "startup_script_behavior": "non-blocking", + "token": "b8d3d938-92ad-478f-85bd-fd5351cd2bbb", "troubleshooting_url": null }, "sensitive_values": { @@ -272,7 +269,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2355126481625628137", + "id": "4692717259652730903", "triggers": null }, "sensitive_values": {}, @@ -297,7 +294,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "0978cc7c-f787-406c-a050-9272bbb52085", + "id": "ea4242b4-e62f-4741-8933-9dc574d79192", "mutable": true, "name": "First parameter from module", "option": null, @@ -324,7 +321,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "cd01d7da-9f56-460d-b163-e88a0a9a5f67", + "id": "df181723-65f5-4ad3-8f7a-058710a8c5ba", "mutable": true, "name": "Second parameter from module", "option": null, @@ -356,7 +353,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "528e845a-843b-48b3-a421-a22340726d5a", + "id": "beb63d1b-a3c1-447c-82fc-0158600033ab", "mutable": true, "name": "First parameter from child module", "option": null, @@ -383,7 +380,7 @@ "display_name": null, "ephemeral": false, "icon": null, - "id": "f486efbb-2fc6-4091-9eca-0088ac6cd3cc", + "id": "06e986b9-b440-4090-8c52-4f889d822aea", "mutable": true, "name": "Second parameter from child module", "option": null, diff --git a/provisioner/terraform/testdata/version.txt b/provisioner/terraform/testdata/version.txt index 66beabb5795e7..db77e0ee9760a 100644 --- a/provisioner/terraform/testdata/version.txt +++ b/provisioner/terraform/testdata/version.txt @@ -1 +1 @@ -1.9.8 +1.10.5 diff --git a/scripts/Dockerfile.base b/scripts/Dockerfile.base index 30ef6802ed716..f9d2bf6594b08 100644 --- a/scripts/Dockerfile.base +++ b/scripts/Dockerfile.base @@ -26,7 +26,7 @@ RUN apk add --no-cache \ # Terraform was disabled in the edge repo due to a build issue. # https://gitlab.alpinelinux.org/alpine/aports/-/commit/f3e263d94cfac02d594bef83790c280e045eba35 # Using wget for now. Note that busybox unzip doesn't support streaming. -RUN ARCH="$(arch)"; if [ "${ARCH}" == "x86_64" ]; then ARCH="amd64"; elif [ "${ARCH}" == "aarch64" ]; then ARCH="arm64"; fi; wget -O /tmp/terraform.zip "https://releases.hashicorp.com/terraform/1.9.8/terraform_1.9.8_linux_${ARCH}.zip" && \ +RUN ARCH="$(arch)"; if [ "${ARCH}" == "x86_64" ]; then ARCH="amd64"; elif [ "${ARCH}" == "aarch64" ]; then ARCH="arm64"; fi; wget -O /tmp/terraform.zip "https://releases.hashicorp.com/terraform/1.10.5/terraform_1.10.5_linux_${ARCH}.zip" && \ busybox unzip /tmp/terraform.zip -d /usr/local/bin && \ rm -f /tmp/terraform.zip && \ chmod +x /usr/local/bin/terraform && \ From 17dbb517adac9b5d386c16516a5886aed1c80615 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 11:00:57 -0800 Subject: [PATCH 4/9] chore: ignore commit metadata check in release script (cherry-pick #16495) (#16831) Cherry-picked chore: ignore commit metadata check in release script (#16495) The `scripts/release/check_commit_metadata.sh` check was too strict for our new cherry-picking process. This turns the error into a warning log. Co-authored-by: Stephen Kirby <58410745+stirby@users.noreply.github.com> --- scripts/release/check_commit_metadata.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/release/check_commit_metadata.sh b/scripts/release/check_commit_metadata.sh index dff4cb1c738fc..f53de8e107430 100755 --- a/scripts/release/check_commit_metadata.sh +++ b/scripts/release/check_commit_metadata.sh @@ -143,7 +143,12 @@ main() { for commit in "${renamed_cherry_pick_commits_pending[@]}"; do log "Checking if pending commit ${commit} has a corresponding cherry-pick..." if [[ ! -v renamed_cherry_pick_commits[${commit}] ]]; then - error "Invariant failed, cherry-picked commit ${commit} has no corresponding original commit" + if [[ ${CODER_IGNORE_MISSING_COMMIT_METADATA:-0} == 1 ]]; then + log "WARNING: Missing original commit for cherry-picked commit ${commit}, but continuing due to CODER_IGNORE_MISSING_COMMIT_METADATA being set." + continue + else + error "Invariant failed, cherry-picked commit ${commit} has no corresponding original commit" + fi fi log "Found matching cherry-pick commit ${commit} -> ${renamed_cherry_pick_commits[${commit}]}" done From 7c4c5048bce9d9bc1a79add3c5e6472d6ee73b85 Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 19:11:13 +0200 Subject: [PATCH 5/9] chore: fix gpg forwarding test (cherry-pick #17355) (#17429) Cherry-picked chore: fix gpg forwarding test (#17355) Co-authored-by: Dean Sheather --- .gitignore | 3 +++ cli/ssh_test.go | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f98101cd7f920..f3bd9b24938e2 100644 --- a/.gitignore +++ b/.gitignore @@ -78,3 +78,6 @@ result # Zed .zed_server + +# dlv debug binaries for go tests +__debug_bin* diff --git a/cli/ssh_test.go b/cli/ssh_test.go index b403f7ff83a8e..659d907188294 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -1843,7 +1843,9 @@ Expire-Date: 0 tpty.WriteLine("gpg --list-keys && echo gpg-''-listkeys-command-done") listKeysOutput := tpty.ExpectMatch("gpg--listkeys-command-done") require.Contains(t, listKeysOutput, "[ultimate] Coder Test ") - require.Contains(t, listKeysOutput, "[ultimate] Dean Sheather (work key) ") + // It's fine that this key is expired. We're just testing that the key trust + // gets synced properly. + require.Contains(t, listKeysOutput, "[ expired] Dean Sheather (work key) ") // Try to sign something. This demonstrates that the forwarding is // working as expected, since the workspace doesn't have access to the From 0f27da03598317bb55f5b57436c172b3d9238fc1 Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Wed, 16 Apr 2025 19:37:59 +0200 Subject: [PATCH 6/9] feat: extend request logs with auth & DB info and log long lived connections early (#17422) --- Makefile | 8 +- coderd/coderd.go | 3 +- coderd/database/dbauthz/dbauthz.go | 28 +- coderd/database/queries.sql.go | 6 +- coderd/database/queries/users.sql | 4 +- coderd/httpmw/apikey.go | 2 + coderd/httpmw/logger.go | 76 ----- coderd/httpmw/loggermw/logger.go | 203 ++++++++++++ .../httpmw/loggermw/logger_internal_test.go | 311 ++++++++++++++++++ .../httpmw/loggermw/loggermock/loggermock.go | 83 +++++ coderd/httpmw/workspaceagentparam.go | 11 + coderd/httpmw/workspaceparam.go | 15 + coderd/provisionerjobs.go | 4 + coderd/provisionerjobs_internal_test.go | 7 + coderd/rbac/authz.go | 25 ++ coderd/workspaceagents.go | 10 + enterprise/coderd/provisionerdaemons.go | 5 + enterprise/wsproxy/wsproxy.go | 3 +- tailnet/test/integration/integration.go | 4 +- 19 files changed, 714 insertions(+), 94 deletions(-) delete mode 100644 coderd/httpmw/logger.go create mode 100644 coderd/httpmw/loggermw/logger.go create mode 100644 coderd/httpmw/loggermw/logger_internal_test.go create mode 100644 coderd/httpmw/loggermw/loggermock/loggermock.go diff --git a/Makefile b/Makefile index d71b1173f36b7..85feb33f8daef 100644 --- a/Makefile +++ b/Makefile @@ -563,8 +563,8 @@ GEN_FILES := \ site/e2e/provisionerGenerated.ts \ examples/examples.gen.json \ $(TAILNETTEST_MOCKS) \ - coderd/database/pubsub/psmock/psmock.go - + coderd/database/pubsub/psmock/psmock.go \ + coderd/httpmw/loggermw/loggermock/loggermock.go # all gen targets should be added here and to gen/mark-fresh gen: gen/db $(GEN_FILES) @@ -598,6 +598,7 @@ gen/mark-fresh: examples/examples.gen.json \ $(TAILNETTEST_MOCKS) \ coderd/database/pubsub/psmock/psmock.go \ + coderd/httpmw/loggermw/loggermock/loggermock.go \ " for file in $$files; do @@ -629,6 +630,9 @@ coderd/database/dbmock/dbmock.go: coderd/database/db.go coderd/database/querier. coderd/database/pubsub/psmock/psmock.go: coderd/database/pubsub/pubsub.go go generate ./coderd/database/pubsub/psmock +coderd/httpmw/loggermw/loggermock/loggermock.go: coderd/httpmw/loggermw/logger.go + go generate ./coderd/httpmw/loggermw/loggermock/ + $(TAILNETTEST_MOCKS): tailnet/coordinator.go tailnet/service.go go generate ./tailnet/tailnettest/ diff --git a/coderd/coderd.go b/coderd/coderd.go index be558797389b9..f6848164cd534 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -63,6 +63,7 @@ import ( "github.com/coder/coder/v2/coderd/healthcheck/derphealth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/metricscache" "github.com/coder/coder/v2/coderd/notifications" "github.com/coder/coder/v2/coderd/portsharing" @@ -787,7 +788,7 @@ func New(options *Options) *API { tracing.Middleware(api.TracerProvider), httpmw.AttachRequestID, httpmw.ExtractRealIP(api.RealIPConfig), - httpmw.Logger(api.Logger), + loggermw.Logger(api.Logger), rolestore.CustomRoleMW, prometheusMW, // Build-Version is helpful for debugging. diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 0ba9e20216b41..25d4073fb944b 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -24,6 +24,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpapi/httpapiconstraints" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/provisionersdk" @@ -162,6 +163,7 @@ func ActorFromContext(ctx context.Context) (rbac.Subject, bool) { var ( subjectProvisionerd = rbac.Subject{ + Type: rbac.SubjectTypeProvisionerd, FriendlyName: "Provisioner Daemon", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -193,6 +195,7 @@ var ( }.WithCachedASTValue() subjectAutostart = rbac.Subject{ + Type: rbac.SubjectTypeAutostart, FriendlyName: "Autostart", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -216,6 +219,7 @@ var ( // See unhanger package. subjectHangDetector = rbac.Subject{ + Type: rbac.SubjectTypeHangDetector, FriendlyName: "Hang Detector", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -236,6 +240,7 @@ var ( // See cryptokeys package. subjectCryptoKeyRotator = rbac.Subject{ + Type: rbac.SubjectTypeCryptoKeyRotator, FriendlyName: "Crypto Key Rotator", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -254,6 +259,7 @@ var ( // See cryptokeys package. subjectCryptoKeyReader = rbac.Subject{ + Type: rbac.SubjectTypeCryptoKeyReader, FriendlyName: "Crypto Key Reader", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -271,6 +277,7 @@ var ( }.WithCachedASTValue() subjectNotifier = rbac.Subject{ + Type: rbac.SubjectTypeNotifier, FriendlyName: "Notifier", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -288,6 +295,7 @@ var ( }.WithCachedASTValue() subjectSystemRestricted = rbac.Subject{ + Type: rbac.SubjectTypeSystemRestricted, FriendlyName: "System", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -323,6 +331,7 @@ var ( }.WithCachedASTValue() subjectSystemReadProvisionerDaemons = rbac.Subject{ + Type: rbac.SubjectTypeSystemReadProvisionerDaemons, FriendlyName: "Provisioner Daemons Reader", ID: uuid.Nil.String(), Roles: rbac.Roles([]rbac.Role{ @@ -343,47 +352,47 @@ var ( // AsProvisionerd returns a context with an actor that has permissions required // for provisionerd to function. func AsProvisionerd(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectProvisionerd) + return As(ctx, subjectProvisionerd) } // AsAutostart returns a context with an actor that has permissions required // for autostart to function. func AsAutostart(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectAutostart) + return As(ctx, subjectAutostart) } // AsHangDetector returns a context with an actor that has permissions required // for unhanger.Detector to function. func AsHangDetector(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectHangDetector) + return As(ctx, subjectHangDetector) } // AsKeyRotator returns a context with an actor that has permissions required for rotating crypto keys. func AsKeyRotator(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectCryptoKeyRotator) + return As(ctx, subjectCryptoKeyRotator) } // AsKeyReader returns a context with an actor that has permissions required for reading crypto keys. func AsKeyReader(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectCryptoKeyReader) + return As(ctx, subjectCryptoKeyReader) } // AsNotifier returns a context with an actor that has permissions required for // creating/reading/updating/deleting notifications. func AsNotifier(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectNotifier) + return As(ctx, subjectNotifier) } // AsSystemRestricted returns a context with an actor that has permissions // required for various system operations (login, logout, metrics cache). func AsSystemRestricted(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectSystemRestricted) + return As(ctx, subjectSystemRestricted) } // AsSystemReadProvisionerDaemons returns a context with an actor that has permissions // to read provisioner daemons. func AsSystemReadProvisionerDaemons(ctx context.Context) context.Context { - return context.WithValue(ctx, authContextKey{}, subjectSystemReadProvisionerDaemons) + return As(ctx, subjectSystemReadProvisionerDaemons) } var AsRemoveActor = rbac.Subject{ @@ -401,6 +410,9 @@ func As(ctx context.Context, actor rbac.Subject) context.Context { // should be removed from the context. return context.WithValue(ctx, authContextKey{}, nil) } + if rlogger := loggermw.RequestLoggerFromContext(ctx); rlogger != nil { + rlogger.WithAuthContext(actor) + } return context.WithValue(ctx, authContextKey{}, actor) } diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 86db8fb66956a..3fec2f94d361e 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -10687,10 +10687,10 @@ func (q *sqlQuerier) GetActiveUserCount(ctx context.Context) (int64, error) { const getAuthorizationUserRoles = `-- name: GetAuthorizationUserRoles :one SELECT - -- username is returned just to help for logging purposes + -- username and email are returned just to help for logging purposes -- status is used to enforce 'suspended' users, as all roles are ignored -- when suspended. - id, username, status, + id, username, status, email, -- All user roles, including their org roles. array_cat( -- All users are members @@ -10731,6 +10731,7 @@ type GetAuthorizationUserRolesRow struct { ID uuid.UUID `db:"id" json:"id"` Username string `db:"username" json:"username"` Status UserStatus `db:"status" json:"status"` + Email string `db:"email" json:"email"` Roles []string `db:"roles" json:"roles"` Groups []string `db:"groups" json:"groups"` } @@ -10744,6 +10745,7 @@ func (q *sqlQuerier) GetAuthorizationUserRoles(ctx context.Context, userID uuid. &i.ID, &i.Username, &i.Status, + &i.Email, pq.Array(&i.Roles), pq.Array(&i.Groups), ) diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index 1f30a2c2c1d24..5e9ffbe50cd31 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -244,10 +244,10 @@ WHERE -- This function returns roles for authorization purposes. Implied member roles -- are included. SELECT - -- username is returned just to help for logging purposes + -- username and email are returned just to help for logging purposes -- status is used to enforce 'suspended' users, as all roles are ignored -- when suspended. - id, username, status, + id, username, status, email, -- All user roles, including their org roles. array_cat( -- All users are members diff --git a/coderd/httpmw/apikey.go b/coderd/httpmw/apikey.go index 38ba74031ba46..2600962e39171 100644 --- a/coderd/httpmw/apikey.go +++ b/coderd/httpmw/apikey.go @@ -465,7 +465,9 @@ func UserRBACSubject(ctx context.Context, db database.Store, userID uuid.UUID, s } actor := rbac.Subject{ + Type: rbac.SubjectTypeUser, FriendlyName: roles.Username, + Email: roles.Email, ID: userID.String(), Roles: rbacRoles, Groups: roles.Groups, diff --git a/coderd/httpmw/logger.go b/coderd/httpmw/logger.go deleted file mode 100644 index 79e95cf859d8e..0000000000000 --- a/coderd/httpmw/logger.go +++ /dev/null @@ -1,76 +0,0 @@ -package httpmw - -import ( - "context" - "fmt" - "net/http" - "time" - - "cdr.dev/slog" - "github.com/coder/coder/v2/coderd/httpapi" - "github.com/coder/coder/v2/coderd/tracing" -) - -func Logger(log slog.Logger) func(next http.Handler) http.Handler { - return func(next http.Handler) http.Handler { - return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - start := time.Now() - - sw, ok := rw.(*tracing.StatusWriter) - if !ok { - panic(fmt.Sprintf("ResponseWriter not a *tracing.StatusWriter; got %T", rw)) - } - - httplog := log.With( - slog.F("host", httpapi.RequestHost(r)), - slog.F("path", r.URL.Path), - slog.F("proto", r.Proto), - slog.F("remote_addr", r.RemoteAddr), - // Include the start timestamp in the log so that we have the - // source of truth. There is at least a theoretical chance that - // there can be a delay between `next.ServeHTTP` ending and us - // actually logging the request. This can also be useful when - // filtering logs that started at a certain time (compared to - // trying to compute the value). - slog.F("start", start), - ) - - next.ServeHTTP(sw, r) - - end := time.Now() - - // Don't log successful health check requests. - if r.URL.Path == "/api/v2" && sw.Status == http.StatusOK { - return - } - - httplog = httplog.With( - slog.F("took", end.Sub(start)), - slog.F("status_code", sw.Status), - slog.F("latency_ms", float64(end.Sub(start)/time.Millisecond)), - ) - - // For status codes 400 and higher we - // want to log the response body. - if sw.Status >= http.StatusInternalServerError { - httplog = httplog.With( - slog.F("response_body", string(sw.ResponseBody())), - ) - } - - // We should not log at level ERROR for 5xx status codes because 5xx - // includes proxy errors etc. It also causes slogtest to fail - // instantly without an error message by default. - logLevelFn := httplog.Debug - if sw.Status >= http.StatusInternalServerError { - logLevelFn = httplog.Warn - } - - // We already capture most of this information in the span (minus - // the response body which we don't want to capture anyways). - tracing.RunWithoutSpan(r.Context(), func(ctx context.Context) { - logLevelFn(ctx, r.Method) - }) - }) - } -} diff --git a/coderd/httpmw/loggermw/logger.go b/coderd/httpmw/loggermw/logger.go new file mode 100644 index 0000000000000..9eeb07a5f10e5 --- /dev/null +++ b/coderd/httpmw/loggermw/logger.go @@ -0,0 +1,203 @@ +package loggermw + +import ( + "context" + "fmt" + "net/http" + "sync" + "time" + + "github.com/go-chi/chi/v5" + + "cdr.dev/slog" + "github.com/coder/coder/v2/coderd/httpapi" + "github.com/coder/coder/v2/coderd/rbac" + "github.com/coder/coder/v2/coderd/tracing" +) + +func Logger(log slog.Logger) func(next http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + start := time.Now() + + sw, ok := rw.(*tracing.StatusWriter) + if !ok { + panic(fmt.Sprintf("ResponseWriter not a *tracing.StatusWriter; got %T", rw)) + } + + httplog := log.With( + slog.F("host", httpapi.RequestHost(r)), + slog.F("path", r.URL.Path), + slog.F("proto", r.Proto), + slog.F("remote_addr", r.RemoteAddr), + // Include the start timestamp in the log so that we have the + // source of truth. There is at least a theoretical chance that + // there can be a delay between `next.ServeHTTP` ending and us + // actually logging the request. This can also be useful when + // filtering logs that started at a certain time (compared to + // trying to compute the value). + slog.F("start", start), + ) + + logContext := NewRequestLogger(httplog, r.Method, start) + + ctx := WithRequestLogger(r.Context(), logContext) + + next.ServeHTTP(sw, r.WithContext(ctx)) + + // Don't log successful health check requests. + if r.URL.Path == "/api/v2" && sw.Status == http.StatusOK { + return + } + + // For status codes 500 and higher we + // want to log the response body. + if sw.Status >= http.StatusInternalServerError { + logContext.WithFields( + slog.F("response_body", string(sw.ResponseBody())), + ) + } + + logContext.WriteLog(r.Context(), sw.Status) + }) + } +} + +type RequestLogger interface { + WithFields(fields ...slog.Field) + WriteLog(ctx context.Context, status int) + WithAuthContext(actor rbac.Subject) +} + +type SlogRequestLogger struct { + log slog.Logger + written bool + message string + start time.Time + // Protects actors map for concurrent writes. + mu sync.RWMutex + actors map[rbac.SubjectType]rbac.Subject +} + +var _ RequestLogger = &SlogRequestLogger{} + +func NewRequestLogger(log slog.Logger, message string, start time.Time) RequestLogger { + return &SlogRequestLogger{ + log: log, + written: false, + message: message, + start: start, + actors: make(map[rbac.SubjectType]rbac.Subject), + } +} + +func (c *SlogRequestLogger) WithFields(fields ...slog.Field) { + c.log = c.log.With(fields...) +} + +func (c *SlogRequestLogger) WithAuthContext(actor rbac.Subject) { + c.mu.Lock() + defer c.mu.Unlock() + c.actors[actor.Type] = actor +} + +func (c *SlogRequestLogger) addAuthContextFields() { + c.mu.RLock() + defer c.mu.RUnlock() + + usr, ok := c.actors[rbac.SubjectTypeUser] + if ok { + c.log = c.log.With( + slog.F("requestor_id", usr.ID), + slog.F("requestor_name", usr.FriendlyName), + slog.F("requestor_email", usr.Email), + ) + } else { + // If there is no user, we log the requestor name for the first + // actor in a defined order. + for _, v := range actorLogOrder { + subj, ok := c.actors[v] + if !ok { + continue + } + c.log = c.log.With( + slog.F("requestor_name", subj.FriendlyName), + ) + break + } + } +} + +var actorLogOrder = []rbac.SubjectType{ + rbac.SubjectTypeAutostart, + rbac.SubjectTypeCryptoKeyReader, + rbac.SubjectTypeCryptoKeyRotator, + rbac.SubjectTypeHangDetector, + rbac.SubjectTypeNotifier, + rbac.SubjectTypePrebuildsOrchestrator, + rbac.SubjectTypeProvisionerd, + rbac.SubjectTypeResourceMonitor, + rbac.SubjectTypeSystemReadProvisionerDaemons, + rbac.SubjectTypeSystemRestricted, +} + +func (c *SlogRequestLogger) WriteLog(ctx context.Context, status int) { + if c.written { + return + } + c.written = true + end := time.Now() + + // Right before we write the log, we try to find the user in the actors + // and add the fields to the log. + c.addAuthContextFields() + + logger := c.log.With( + slog.F("took", end.Sub(c.start)), + slog.F("status_code", status), + slog.F("latency_ms", float64(end.Sub(c.start)/time.Millisecond)), + ) + + // If the request is routed, add the route parameters to the log. + if chiCtx := chi.RouteContext(ctx); chiCtx != nil { + urlParams := chiCtx.URLParams + routeParamsFields := make([]slog.Field, 0, len(urlParams.Keys)) + + for k, v := range urlParams.Keys { + if urlParams.Values[k] != "" { + routeParamsFields = append(routeParamsFields, slog.F("params_"+v, urlParams.Values[k])) + } + } + + if len(routeParamsFields) > 0 { + logger = logger.With(routeParamsFields...) + } + } + + // We already capture most of this information in the span (minus + // the response body which we don't want to capture anyways). + tracing.RunWithoutSpan(ctx, func(ctx context.Context) { + // We should not log at level ERROR for 5xx status codes because 5xx + // includes proxy errors etc. It also causes slogtest to fail + // instantly without an error message by default. + if status >= http.StatusInternalServerError { + logger.Warn(ctx, c.message) + } else { + logger.Debug(ctx, c.message) + } + }) +} + +type logContextKey struct{} + +func WithRequestLogger(ctx context.Context, rl RequestLogger) context.Context { + return context.WithValue(ctx, logContextKey{}, rl) +} + +func RequestLoggerFromContext(ctx context.Context) RequestLogger { + val := ctx.Value(logContextKey{}) + if logCtx, ok := val.(RequestLogger); ok { + return logCtx + } + return nil +} diff --git a/coderd/httpmw/loggermw/logger_internal_test.go b/coderd/httpmw/loggermw/logger_internal_test.go new file mode 100644 index 0000000000000..e88f8a69c178e --- /dev/null +++ b/coderd/httpmw/loggermw/logger_internal_test.go @@ -0,0 +1,311 @@ +package loggermw + +import ( + "context" + "net/http" + "net/http/httptest" + "slices" + "strings" + "sync" + "testing" + "time" + + "github.com/go-chi/chi/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "cdr.dev/slog" + "github.com/coder/coder/v2/coderd/tracing" + "github.com/coder/coder/v2/testutil" + "github.com/coder/websocket" +) + +func TestRequestLogger_WriteLog(t *testing.T) { + t.Parallel() + ctx := context.Background() + + sink := &fakeSink{} + logger := slog.Make(sink) + logger = logger.Leveled(slog.LevelDebug) + logCtx := NewRequestLogger(logger, "GET", time.Now()) + + // Add custom fields + logCtx.WithFields( + slog.F("custom_field", "custom_value"), + ) + + // Write log for 200 status + logCtx.WriteLog(ctx, http.StatusOK) + + require.Len(t, sink.entries, 1, "log was written twice") + + require.Equal(t, sink.entries[0].Message, "GET") + + require.Equal(t, sink.entries[0].Fields[0].Value, "custom_value") + + // Attempt to write again (should be skipped). + logCtx.WriteLog(ctx, http.StatusInternalServerError) + + require.Len(t, sink.entries, 1, "log was written twice") +} + +func TestLoggerMiddleware_SingleRequest(t *testing.T) { + t.Parallel() + + sink := &fakeSink{} + logger := slog.Make(sink) + logger = logger.Leveled(slog.LevelDebug) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) + defer cancel() + + // Create a test handler to simulate an HTTP request + testHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusOK) + _, _ = rw.Write([]byte("OK")) + }) + + // Wrap the test handler with the Logger middleware + loggerMiddleware := Logger(logger) + wrappedHandler := loggerMiddleware(testHandler) + + // Create a test HTTP request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/test-path", nil) + require.NoError(t, err, "failed to create request") + + sw := &tracing.StatusWriter{ResponseWriter: httptest.NewRecorder()} + + // Serve the request + wrappedHandler.ServeHTTP(sw, req) + + require.Len(t, sink.entries, 1, "log was written twice") + + require.Equal(t, sink.entries[0].Message, "GET") + + fieldsMap := make(map[string]any) + for _, field := range sink.entries[0].Fields { + fieldsMap[field.Name] = field.Value + } + + // Check that the log contains the expected fields + requiredFields := []string{"host", "path", "proto", "remote_addr", "start", "took", "status_code", "latency_ms"} + for _, field := range requiredFields { + _, exists := fieldsMap[field] + require.True(t, exists, "field %q is missing in log fields", field) + } + + require.Len(t, sink.entries[0].Fields, len(requiredFields), "log should contain only the required fields") + + // Check value of the status code + require.Equal(t, fieldsMap["status_code"], http.StatusOK) +} + +func TestLoggerMiddleware_WebSocket(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) + defer cancel() + + sink := &fakeSink{ + newEntries: make(chan slog.SinkEntry, 2), + } + logger := slog.Make(sink) + logger = logger.Leveled(slog.LevelDebug) + done := make(chan struct{}) + wg := sync.WaitGroup{} + // Create a test handler to simulate a WebSocket connection + testHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + conn, err := websocket.Accept(rw, r, nil) + if !assert.NoError(t, err, "failed to accept websocket") { + return + } + defer conn.Close(websocket.StatusGoingAway, "") + + requestLgr := RequestLoggerFromContext(r.Context()) + requestLgr.WriteLog(r.Context(), http.StatusSwitchingProtocols) + // Block so we can be sure the end of the middleware isn't being called. + wg.Wait() + }) + + // Wrap the test handler with the Logger middleware + loggerMiddleware := Logger(logger) + wrappedHandler := loggerMiddleware(testHandler) + + // RequestLogger expects the ResponseWriter to be *tracing.StatusWriter + customHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + defer close(done) + sw := &tracing.StatusWriter{ResponseWriter: rw} + wrappedHandler.ServeHTTP(sw, r) + }) + + srv := httptest.NewServer(customHandler) + defer srv.Close() + wg.Add(1) + // nolint: bodyclose + conn, _, err := websocket.Dial(ctx, srv.URL, nil) + require.NoError(t, err, "failed to dial WebSocket") + defer conn.Close(websocket.StatusNormalClosure, "") + + // Wait for the log from within the handler + newEntry := testutil.RequireRecvCtx(ctx, t, sink.newEntries) + require.Equal(t, newEntry.Message, "GET") + + // Signal the websocket handler to return (and read to handle the close frame) + wg.Done() + _, _, err = conn.Read(ctx) + require.ErrorAs(t, err, &websocket.CloseError{}, "websocket read should fail with close error") + + // Wait for the request to finish completely and verify we only logged once + _ = testutil.RequireRecvCtx(ctx, t, done) + require.Len(t, sink.entries, 1, "log was written twice") +} + +func TestRequestLogger_HTTPRouteParams(t *testing.T) { + t.Parallel() + + sink := &fakeSink{} + logger := slog.Make(sink) + logger = logger.Leveled(slog.LevelDebug) + + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) + defer cancel() + + chiCtx := chi.NewRouteContext() + chiCtx.URLParams.Add("workspace", "test-workspace") + chiCtx.URLParams.Add("agent", "test-agent") + + ctx = context.WithValue(ctx, chi.RouteCtxKey, chiCtx) + + // Create a test handler to simulate an HTTP request + testHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(http.StatusOK) + _, _ = rw.Write([]byte("OK")) + }) + + // Wrap the test handler with the Logger middleware + loggerMiddleware := Logger(logger) + wrappedHandler := loggerMiddleware(testHandler) + + // Create a test HTTP request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/test-path/}", nil) + require.NoError(t, err, "failed to create request") + + sw := &tracing.StatusWriter{ResponseWriter: httptest.NewRecorder()} + + // Serve the request + wrappedHandler.ServeHTTP(sw, req) + + fieldsMap := make(map[string]any) + for _, field := range sink.entries[0].Fields { + fieldsMap[field.Name] = field.Value + } + + // Check that the log contains the expected fields + requiredFields := []string{"workspace", "agent"} + for _, field := range requiredFields { + _, exists := fieldsMap["params_"+field] + require.True(t, exists, "field %q is missing in log fields", field) + } +} + +func TestRequestLogger_RouteParamsLogging(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + params map[string]string + expectedFields []string + }{ + { + name: "EmptyParams", + params: map[string]string{}, + expectedFields: []string{}, + }, + { + name: "SingleParam", + params: map[string]string{ + "workspace": "test-workspace", + }, + expectedFields: []string{"params_workspace"}, + }, + { + name: "MultipleParams", + params: map[string]string{ + "workspace": "test-workspace", + "agent": "test-agent", + "user": "test-user", + }, + expectedFields: []string{"params_workspace", "params_agent", "params_user"}, + }, + { + name: "EmptyValueParam", + params: map[string]string{ + "workspace": "test-workspace", + "agent": "", + }, + expectedFields: []string{"params_workspace"}, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + sink := &fakeSink{} + logger := slog.Make(sink) + logger = logger.Leveled(slog.LevelDebug) + + // Create a route context with the test parameters + chiCtx := chi.NewRouteContext() + for key, value := range tt.params { + chiCtx.URLParams.Add(key, value) + } + + ctx := context.WithValue(context.Background(), chi.RouteCtxKey, chiCtx) + logCtx := NewRequestLogger(logger, "GET", time.Now()) + + // Write the log + logCtx.WriteLog(ctx, http.StatusOK) + + require.Len(t, sink.entries, 1, "expected exactly one log entry") + + // Convert fields to map for easier checking + fieldsMap := make(map[string]any) + for _, field := range sink.entries[0].Fields { + fieldsMap[field.Name] = field.Value + } + + // Verify expected fields are present + for _, field := range tt.expectedFields { + value, exists := fieldsMap[field] + require.True(t, exists, "field %q should be present in log", field) + require.Equal(t, tt.params[strings.TrimPrefix(field, "params_")], value, "field %q has incorrect value", field) + } + + // Verify no unexpected fields are present + for field := range fieldsMap { + if field == "took" || field == "status_code" || field == "latency_ms" { + continue // Skip standard fields + } + require.True(t, slices.Contains(tt.expectedFields, field), "unexpected field %q in log", field) + } + }) + } +} + +type fakeSink struct { + entries []slog.SinkEntry + newEntries chan slog.SinkEntry +} + +func (s *fakeSink) LogEntry(_ context.Context, e slog.SinkEntry) { + s.entries = append(s.entries, e) + if s.newEntries != nil { + select { + case s.newEntries <- e: + default: + } + } +} + +func (*fakeSink) Sync() {} diff --git a/coderd/httpmw/loggermw/loggermock/loggermock.go b/coderd/httpmw/loggermw/loggermock/loggermock.go new file mode 100644 index 0000000000000..008f862107ae6 --- /dev/null +++ b/coderd/httpmw/loggermw/loggermock/loggermock.go @@ -0,0 +1,83 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/coder/coder/v2/coderd/httpmw/loggermw (interfaces: RequestLogger) +// +// Generated by this command: +// +// mockgen -destination=loggermock/loggermock.go -package=loggermock . RequestLogger +// + +// Package loggermock is a generated GoMock package. +package loggermock + +import ( + context "context" + reflect "reflect" + + slog "cdr.dev/slog" + rbac "github.com/coder/coder/v2/coderd/rbac" + gomock "go.uber.org/mock/gomock" +) + +// MockRequestLogger is a mock of RequestLogger interface. +type MockRequestLogger struct { + ctrl *gomock.Controller + recorder *MockRequestLoggerMockRecorder + isgomock struct{} +} + +// MockRequestLoggerMockRecorder is the mock recorder for MockRequestLogger. +type MockRequestLoggerMockRecorder struct { + mock *MockRequestLogger +} + +// NewMockRequestLogger creates a new mock instance. +func NewMockRequestLogger(ctrl *gomock.Controller) *MockRequestLogger { + mock := &MockRequestLogger{ctrl: ctrl} + mock.recorder = &MockRequestLoggerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRequestLogger) EXPECT() *MockRequestLoggerMockRecorder { + return m.recorder +} + +// WithAuthContext mocks base method. +func (m *MockRequestLogger) WithAuthContext(actor rbac.Subject) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "WithAuthContext", actor) +} + +// WithAuthContext indicates an expected call of WithAuthContext. +func (mr *MockRequestLoggerMockRecorder) WithAuthContext(actor any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithAuthContext", reflect.TypeOf((*MockRequestLogger)(nil).WithAuthContext), actor) +} + +// WithFields mocks base method. +func (m *MockRequestLogger) WithFields(fields ...slog.Field) { + m.ctrl.T.Helper() + varargs := []any{} + for _, a := range fields { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "WithFields", varargs...) +} + +// WithFields indicates an expected call of WithFields. +func (mr *MockRequestLoggerMockRecorder) WithFields(fields ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WithFields", reflect.TypeOf((*MockRequestLogger)(nil).WithFields), fields...) +} + +// WriteLog mocks base method. +func (m *MockRequestLogger) WriteLog(ctx context.Context, status int) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "WriteLog", ctx, status) +} + +// WriteLog indicates an expected call of WriteLog. +func (mr *MockRequestLoggerMockRecorder) WriteLog(ctx, status any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteLog", reflect.TypeOf((*MockRequestLogger)(nil).WriteLog), ctx, status) +} diff --git a/coderd/httpmw/workspaceagentparam.go b/coderd/httpmw/workspaceagentparam.go index a47ce3c377ae0..434e057c0eccc 100644 --- a/coderd/httpmw/workspaceagentparam.go +++ b/coderd/httpmw/workspaceagentparam.go @@ -6,8 +6,11 @@ import ( "github.com/go-chi/chi/v5" + "cdr.dev/slog" + "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/httpapi" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/codersdk" ) @@ -81,6 +84,14 @@ func ExtractWorkspaceAgentParam(db database.Store) func(http.Handler) http.Handl ctx = context.WithValue(ctx, workspaceAgentParamContextKey{}, agent) chi.RouteContext(ctx).URLParams.Add("workspace", build.WorkspaceID.String()) + + if rlogger := loggermw.RequestLoggerFromContext(ctx); rlogger != nil { + rlogger.WithFields( + slog.F("workspace_name", resource.Name), + slog.F("agent_name", agent.Name), + ) + } + next.ServeHTTP(rw, r.WithContext(ctx)) }) } diff --git a/coderd/httpmw/workspaceparam.go b/coderd/httpmw/workspaceparam.go index 21e8dcfd62863..0c4e4f77354fc 100644 --- a/coderd/httpmw/workspaceparam.go +++ b/coderd/httpmw/workspaceparam.go @@ -9,8 +9,11 @@ import ( "github.com/go-chi/chi/v5" "github.com/google/uuid" + "cdr.dev/slog" + "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/httpapi" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/codersdk" ) @@ -48,6 +51,11 @@ func ExtractWorkspaceParam(db database.Store) func(http.Handler) http.Handler { } ctx = context.WithValue(ctx, workspaceParamContextKey{}, workspace) + + if rlogger := loggermw.RequestLoggerFromContext(ctx); rlogger != nil { + rlogger.WithFields(slog.F("workspace_name", workspace.Name)) + } + next.ServeHTTP(rw, r.WithContext(ctx)) }) } @@ -154,6 +162,13 @@ func ExtractWorkspaceAndAgentParam(db database.Store) func(http.Handler) http.Ha ctx = context.WithValue(ctx, workspaceParamContextKey{}, workspace) ctx = context.WithValue(ctx, workspaceAgentParamContextKey{}, agent) + + if rlogger := loggermw.RequestLoggerFromContext(ctx); rlogger != nil { + rlogger.WithFields( + slog.F("workspace_name", workspace.Name), + slog.F("agent_name", agent.Name), + ) + } next.ServeHTTP(rw, r.WithContext(ctx)) }) } diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index 591c60855a65e..3096d2b47debb 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -20,6 +20,7 @@ import ( "github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/policy" "github.com/coder/coder/v2/coderd/util/slice" @@ -536,6 +537,9 @@ func (f *logFollower) follow() { return } + // Log the request immediately instead of after it completes. + loggermw.RequestLoggerFromContext(f.ctx).WriteLog(f.ctx, http.StatusAccepted) + // no need to wait if the job is done if f.complete { return diff --git a/coderd/provisionerjobs_internal_test.go b/coderd/provisionerjobs_internal_test.go index af5a7d66a6f4c..f3bc2eb1dea99 100644 --- a/coderd/provisionerjobs_internal_test.go +++ b/coderd/provisionerjobs_internal_test.go @@ -19,6 +19,8 @@ import ( "github.com/coder/coder/v2/coderd/database/dbmock" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/pubsub" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw/loggermock" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/provisionersdk" "github.com/coder/coder/v2/testutil" @@ -305,11 +307,16 @@ func Test_logFollower_EndOfLogs(t *testing.T) { JobStatus: database.ProvisionerJobStatusRunning, } + mockLogger := loggermock.NewMockRequestLogger(ctrl) + mockLogger.EXPECT().WriteLog(gomock.Any(), http.StatusAccepted).Times(1) + ctx = loggermw.WithRequestLogger(ctx, mockLogger) + // we need an HTTP server to get a websocket srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { uut := newLogFollower(ctx, logger, mDB, ps, rw, r, job, 0) uut.follow() })) + defer srv.Close() // job was incomplete when we create the logFollower, and still incomplete when it queries diff --git a/coderd/rbac/authz.go b/coderd/rbac/authz.go index aaba7d6eae3af..02268e052d2e2 100644 --- a/coderd/rbac/authz.go +++ b/coderd/rbac/authz.go @@ -57,6 +57,23 @@ func hashAuthorizeCall(actor Subject, action policy.Action, object Object) [32]b return hashOut } +// SubjectType represents the type of subject in the RBAC system. +type SubjectType string + +const ( + SubjectTypeUser SubjectType = "user" + SubjectTypeProvisionerd SubjectType = "provisionerd" + SubjectTypeAutostart SubjectType = "autostart" + SubjectTypeHangDetector SubjectType = "hang_detector" + SubjectTypeResourceMonitor SubjectType = "resource_monitor" + SubjectTypeCryptoKeyRotator SubjectType = "crypto_key_rotator" + SubjectTypeCryptoKeyReader SubjectType = "crypto_key_reader" + SubjectTypePrebuildsOrchestrator SubjectType = "prebuilds_orchestrator" + SubjectTypeSystemReadProvisionerDaemons SubjectType = "system_read_provisioner_daemons" + SubjectTypeSystemRestricted SubjectType = "system_restricted" + SubjectTypeNotifier SubjectType = "notifier" +) + // Subject is a struct that contains all the elements of a subject in an rbac // authorize. type Subject struct { @@ -66,6 +83,14 @@ type Subject struct { // external workspace proxy or other service type actor. FriendlyName string + // Email is entirely optional and is used for logging and debugging + // It is not used in any functional way. + Email string + + // Type indicates what kind of subject this is (user, system, provisioner, etc.) + // It is not used in any functional way, only for logging. + Type SubjectType + ID string Roles ExpandableRoles Groups []string diff --git a/coderd/workspaceagents.go b/coderd/workspaceagents.go index 026c3581ff14d..390caeb7c2ac3 100644 --- a/coderd/workspaceagents.go +++ b/coderd/workspaceagents.go @@ -31,6 +31,7 @@ import ( "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/jwtutils" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/policy" @@ -462,6 +463,9 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) { t := time.NewTicker(recheckInterval) defer t.Stop() + // Log the request immediately instead of after it completes. + loggermw.RequestLoggerFromContext(ctx).WriteLog(ctx, http.StatusAccepted) + go func() { defer func() { logger.Debug(ctx, "end log streaming loop") @@ -742,6 +746,9 @@ func (api *API) derpMapUpdates(rw http.ResponseWriter, r *http.Request) { encoder := wsjson.NewEncoder[*tailcfg.DERPMap](ws, websocket.MessageBinary) defer encoder.Close(websocket.StatusGoingAway) + // Log the request immediately instead of after it completes. + loggermw.RequestLoggerFromContext(ctx).WriteLog(ctx, http.StatusAccepted) + go func(ctx context.Context) { // TODO(mafredri): Is this too frequent? Use separate ping disconnect timeout? t := time.NewTicker(api.AgentConnectionUpdateFrequency) @@ -1105,6 +1112,9 @@ func (api *API) watchWorkspaceAgentMetadata(rw http.ResponseWriter, r *http.Requ sendTicker := time.NewTicker(sendInterval) defer sendTicker.Stop() + // Log the request immediately instead of after it completes. + loggermw.RequestLoggerFromContext(ctx).WriteLog(ctx, http.StatusAccepted) + // Send initial metadata. sendMetadata() diff --git a/enterprise/coderd/provisionerdaemons.go b/enterprise/coderd/provisionerdaemons.go index f4335438654b5..ccd893bb25e82 100644 --- a/enterprise/coderd/provisionerdaemons.go +++ b/enterprise/coderd/provisionerdaemons.go @@ -24,6 +24,7 @@ import ( "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/provisionerdserver" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/policy" @@ -381,6 +382,10 @@ func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request) logger.Debug(ctx, "drpc server error", slog.Error(err)) }, }) + + // Log the request immediately instead of after it completes. + loggermw.RequestLoggerFromContext(ctx).WriteLog(ctx, http.StatusAccepted) + err = server.Serve(ctx, session) srvCancel() logger.Info(ctx, "provisioner daemon disconnected", slog.Error(err)) diff --git a/enterprise/wsproxy/wsproxy.go b/enterprise/wsproxy/wsproxy.go index af4d5064f4531..81b800c536a0f 100644 --- a/enterprise/wsproxy/wsproxy.go +++ b/enterprise/wsproxy/wsproxy.go @@ -32,6 +32,7 @@ import ( "github.com/coder/coder/v2/coderd/cryptokeys" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/tracing" "github.com/coder/coder/v2/coderd/workspaceapps" "github.com/coder/coder/v2/codersdk" @@ -336,7 +337,7 @@ func New(ctx context.Context, opts *Options) (*Server, error) { tracing.Middleware(s.TracerProvider), httpmw.AttachRequestID, httpmw.ExtractRealIP(s.Options.RealIPConfig), - httpmw.Logger(s.Logger), + loggermw.Logger(s.Logger), prometheusMW, corsMW, diff --git a/tailnet/test/integration/integration.go b/tailnet/test/integration/integration.go index 87f0cdcf4e148..d2d960807b142 100644 --- a/tailnet/test/integration/integration.go +++ b/tailnet/test/integration/integration.go @@ -33,7 +33,7 @@ import ( "cdr.dev/slog" "github.com/coder/coder/v2/coderd/httpapi" - "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/coderd/httpmw/loggermw" "github.com/coder/coder/v2/coderd/tracing" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/tailnet" @@ -200,7 +200,7 @@ func (o SimpleServerOptions) Router(t *testing.T, logger slog.Logger) *chi.Mux { }) }, tracing.StatusWriterMiddleware, - httpmw.Logger(logger), + loggermw.Logger(logger), ) r.Route("/derp", func(r chi.Router) { From bda202f3f19bb9e06b7c812264384b458af7363b Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Fri, 18 Apr 2025 21:37:19 +0200 Subject: [PATCH 7/9] feat: add path & method labels to prometheus metrics (cherry-pick #17362) (#17416) --- coderd/httpmw/prometheus.go | 52 ++++++++++++++---- coderd/httpmw/prometheus_test.go | 91 ++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 10 deletions(-) diff --git a/coderd/httpmw/prometheus.go b/coderd/httpmw/prometheus.go index b96be84e879e3..8b7b33381c74d 100644 --- a/coderd/httpmw/prometheus.go +++ b/coderd/httpmw/prometheus.go @@ -3,6 +3,7 @@ package httpmw import ( "net/http" "strconv" + "strings" "time" "github.com/go-chi/chi/v5" @@ -22,18 +23,18 @@ func Prometheus(register prometheus.Registerer) func(http.Handler) http.Handler Name: "requests_processed_total", Help: "The total number of processed API requests", }, []string{"code", "method", "path"}) - requestsConcurrent := factory.NewGauge(prometheus.GaugeOpts{ + requestsConcurrent := factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: "coderd", Subsystem: "api", Name: "concurrent_requests", Help: "The number of concurrent API requests.", - }) - websocketsConcurrent := factory.NewGauge(prometheus.GaugeOpts{ + }, []string{"method", "path"}) + websocketsConcurrent := factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: "coderd", Subsystem: "api", Name: "concurrent_websockets", Help: "The total number of concurrent API websockets.", - }) + }, []string{"path"}) websocketsDist := factory.NewHistogramVec(prometheus.HistogramOpts{ Namespace: "coderd", Subsystem: "api", @@ -61,7 +62,6 @@ func Prometheus(register prometheus.Registerer) func(http.Handler) http.Handler var ( start = time.Now() method = r.Method - rctx = chi.RouteContext(r.Context()) ) sw, ok := w.(*tracing.StatusWriter) @@ -72,16 +72,18 @@ func Prometheus(register prometheus.Registerer) func(http.Handler) http.Handler var ( dist *prometheus.HistogramVec distOpts []string + path = getRoutePattern(r) ) + // We want to count WebSockets separately. if httpapi.IsWebsocketUpgrade(r) { - websocketsConcurrent.Inc() - defer websocketsConcurrent.Dec() + websocketsConcurrent.WithLabelValues(path).Inc() + defer websocketsConcurrent.WithLabelValues(path).Dec() dist = websocketsDist } else { - requestsConcurrent.Inc() - defer requestsConcurrent.Dec() + requestsConcurrent.WithLabelValues(method, path).Inc() + defer requestsConcurrent.WithLabelValues(method, path).Dec() dist = requestsDist distOpts = []string{method} @@ -89,7 +91,6 @@ func Prometheus(register prometheus.Registerer) func(http.Handler) http.Handler next.ServeHTTP(w, r) - path := rctx.RoutePattern() distOpts = append(distOpts, path) statusStr := strconv.Itoa(sw.Status) @@ -98,3 +99,34 @@ func Prometheus(register prometheus.Registerer) func(http.Handler) http.Handler }) } } + +func getRoutePattern(r *http.Request) string { + rctx := chi.RouteContext(r.Context()) + if rctx == nil { + return "" + } + + if pattern := rctx.RoutePattern(); pattern != "" { + // Pattern is already available + return pattern + } + + routePath := r.URL.Path + if r.URL.RawPath != "" { + routePath = r.URL.RawPath + } + + tctx := chi.NewRouteContext() + routes := rctx.Routes + if routes != nil && !routes.Match(tctx, r.Method, routePath) { + // No matching pattern. /api/* requests will be matched as "UNKNOWN" + // All other ones will be matched as "STATIC". + if strings.HasPrefix(routePath, "/api/") { + return "UNKNOWN" + } + return "STATIC" + } + + // tctx has the updated pattern, since Match mutates it + return tctx.RoutePattern() +} diff --git a/coderd/httpmw/prometheus_test.go b/coderd/httpmw/prometheus_test.go index a51eea5d00312..d40558f5ca5e7 100644 --- a/coderd/httpmw/prometheus_test.go +++ b/coderd/httpmw/prometheus_test.go @@ -8,14 +8,19 @@ import ( "github.com/go-chi/chi/v5" "github.com/prometheus/client_golang/prometheus" + cm "github.com/prometheus/client_model/go" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/tracing" + "github.com/coder/coder/v2/testutil" + "github.com/coder/websocket" ) func TestPrometheus(t *testing.T) { t.Parallel() + t.Run("All", func(t *testing.T) { t.Parallel() req := httptest.NewRequest("GET", "/", nil) @@ -29,4 +34,90 @@ func TestPrometheus(t *testing.T) { require.NoError(t, err) require.Greater(t, len(metrics), 0) }) + + t.Run("Concurrent", func(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) + defer cancel() + + reg := prometheus.NewRegistry() + promMW := httpmw.Prometheus(reg) + + // Create a test handler to simulate a WebSocket connection + testHandler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + conn, err := websocket.Accept(rw, r, nil) + if !assert.NoError(t, err, "failed to accept websocket") { + return + } + defer conn.Close(websocket.StatusGoingAway, "") + }) + + wrappedHandler := promMW(testHandler) + + r := chi.NewRouter() + r.Use(tracing.StatusWriterMiddleware, promMW) + r.Get("/api/v2/build/{build}/logs", func(rw http.ResponseWriter, r *http.Request) { + wrappedHandler.ServeHTTP(rw, r) + }) + + srv := httptest.NewServer(r) + defer srv.Close() + // nolint: bodyclose + conn, _, err := websocket.Dial(ctx, srv.URL+"/api/v2/build/1/logs", nil) + require.NoError(t, err, "failed to dial WebSocket") + defer conn.Close(websocket.StatusNormalClosure, "") + + metrics, err := reg.Gather() + require.NoError(t, err) + require.Greater(t, len(metrics), 0) + metricLabels := getMetricLabels(metrics) + + concurrentWebsockets, ok := metricLabels["coderd_api_concurrent_websockets"] + require.True(t, ok, "coderd_api_concurrent_websockets metric not found") + require.Equal(t, "/api/v2/build/{build}/logs", concurrentWebsockets["path"]) + }) + + t.Run("UserRoute", func(t *testing.T) { + t.Parallel() + reg := prometheus.NewRegistry() + promMW := httpmw.Prometheus(reg) + + r := chi.NewRouter() + r.With(promMW).Get("/api/v2/users/{user}", func(w http.ResponseWriter, r *http.Request) {}) + + req := httptest.NewRequest("GET", "/api/v2/users/john", nil) + + sw := &tracing.StatusWriter{ResponseWriter: httptest.NewRecorder()} + + r.ServeHTTP(sw, req) + + metrics, err := reg.Gather() + require.NoError(t, err) + require.Greater(t, len(metrics), 0) + metricLabels := getMetricLabels(metrics) + + reqProcessed, ok := metricLabels["coderd_api_requests_processed_total"] + require.True(t, ok, "coderd_api_requests_processed_total metric not found") + require.Equal(t, "/api/v2/users/{user}", reqProcessed["path"]) + require.Equal(t, "GET", reqProcessed["method"]) + + concurrentRequests, ok := metricLabels["coderd_api_concurrent_requests"] + require.True(t, ok, "coderd_api_concurrent_requests metric not found") + require.Equal(t, "/api/v2/users/{user}", concurrentRequests["path"]) + require.Equal(t, "GET", concurrentRequests["method"]) + }) +} + +func getMetricLabels(metrics []*cm.MetricFamily) map[string]map[string]string { + metricLabels := map[string]map[string]string{} + for _, metricFamily := range metrics { + metricName := metricFamily.GetName() + metricLabels[metricName] = map[string]string{} + for _, metric := range metricFamily.GetMetric() { + for _, labelPair := range metric.GetLabel() { + metricLabels[metricName][labelPair.GetName()] = labelPair.GetValue() + } + } + } + return metricLabels } From dd50c4ecc9c4453b208e831ccfcccc2c65e1f2bf Mon Sep 17 00:00:00 2001 From: "gcp-cherry-pick-bot[bot]" <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com> Date: Wed, 23 Apr 2025 17:46:46 +0500 Subject: [PATCH 8/9] fix(scripts/release): handle cherry-pick bot titles in check commit metadata (cherry-pick #17535) (#17537) Co-authored-by: Mathias Fredriksson --- scripts/release/check_commit_metadata.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/release/check_commit_metadata.sh b/scripts/release/check_commit_metadata.sh index f53de8e107430..1368425d00639 100755 --- a/scripts/release/check_commit_metadata.sh +++ b/scripts/release/check_commit_metadata.sh @@ -118,6 +118,23 @@ main() { title2=${parts2[*]:2} fi + # Handle cherry-pick bot, it turns "chore: foo bar (#42)" to + # "chore: foo bar (cherry-pick #42) (#43)". + if [[ ${title1} == *"(cherry-pick #"* ]]; then + title1=${title1%" ("*} + pr=${title1##*#} + pr=${pr%)} + title1=${title1%" ("*} + title1="${title1} (#${pr})"$'\n' + fi + if [[ ${title2} == *"(cherry-pick #"* ]]; then + title2=${title2%" ("*} + pr=${title2##*#} + pr=${pr%)} + title2=${title2%" ("*} + title2="${title2} (#${pr})"$'\n' + fi + if [[ ${title1} != "${title2}" ]]; then log "Invariant failed, cherry-picked commits have different titles: \"${title1%$'\n'}\" != \"${title2%$'\n'}\", attempting to check commit body for cherry-pick information..." From e0ebeebb29eb9b0df2d6c7d62ff55baceb4d287c Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Wed, 30 Apr 2025 00:34:51 +1000 Subject: [PATCH 9/9] chore: apply Dockerfile architecture fixes (#17601) --- scripts/Dockerfile.base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Dockerfile.base b/scripts/Dockerfile.base index f9d2bf6594b08..8090623be8306 100644 --- a/scripts/Dockerfile.base +++ b/scripts/Dockerfile.base @@ -26,7 +26,7 @@ RUN apk add --no-cache \ # Terraform was disabled in the edge repo due to a build issue. # https://gitlab.alpinelinux.org/alpine/aports/-/commit/f3e263d94cfac02d594bef83790c280e045eba35 # Using wget for now. Note that busybox unzip doesn't support streaming. -RUN ARCH="$(arch)"; if [ "${ARCH}" == "x86_64" ]; then ARCH="amd64"; elif [ "${ARCH}" == "aarch64" ]; then ARCH="arm64"; fi; wget -O /tmp/terraform.zip "https://releases.hashicorp.com/terraform/1.10.5/terraform_1.10.5_linux_${ARCH}.zip" && \ +RUN ARCH="$(arch)"; if [ "${ARCH}" == "x86_64" ]; then ARCH="amd64"; elif [ "${ARCH}" == "aarch64" ]; then ARCH="arm64"; elif [ "${ARCH}" == "armv7l" ]; then ARCH="arm"; fi; wget -O /tmp/terraform.zip "https://releases.hashicorp.com/terraform/1.10.5/terraform_1.10.5_linux_${ARCH}.zip" && \ busybox unzip /tmp/terraform.zip -d /usr/local/bin && \ rm -f /tmp/terraform.zip && \ chmod +x /usr/local/bin/terraform && \