mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix(provisioner): make coder_env and coder_script iteration deterministic (#22706)
## Description Fixes https://github.com/coder/coder/issues/21885 When multiple `coder_env` resources define the same key for a single agent, the final environment variable value was non-deterministic because Go maps have random iteration order. The `ConvertState` function iterated over `tfResourcesByLabel` (a map) to associate `coder_env` resources with agents, making the order of `ExtraEnvs` unpredictable across builds. ## Changes - Added `sortedResourcesByType()` helper in `resources.go` that collects resources of a given type from the label map and sorts them by Terraform address before processing - Replaced map iteration for `coder_env` and `coder_script` association with sorted iteration, ensuring deterministic ordering - Added `duplicate-env-keys` test case and fixture verifying that when two `coder_env` resources define the same key, the result is deterministic (sorted by address) ## How it works When duplicate keys exist, the last one by sorted Terraform address wins. For example, `coder_env.path_a` is processed before `coder_env.path_b`, so `path_b`'s value will be the final one in `ExtraEnvs`. Since `provisionerdserver.go` merges `ExtraEnvs` into a map (last wins), this produces stable, predictable results.
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package terraform
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/awalterschulze/gographviz"
|
||||
@@ -634,81 +636,77 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
|
||||
}
|
||||
|
||||
// Associate envs with agents.
|
||||
for _, resources := range tfResourcesByLabel {
|
||||
for _, resource := range resources {
|
||||
if resource.Type != "coder_env" {
|
||||
continue
|
||||
}
|
||||
var attrs agentEnvAttributes
|
||||
err = mapstructure.Decode(resource.AttributeValues, &attrs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode env attributes: %w", err)
|
||||
}
|
||||
// Collect and sort env resources by address for deterministic ordering.
|
||||
// When multiple coder_env resources define the same key, the last one
|
||||
// by sorted address wins, ensuring stable behavior across builds.
|
||||
sortedEnvResources := sortedResourcesByType(tfResourcesByLabel, "coder_env")
|
||||
for _, resource := range sortedEnvResources {
|
||||
var attrs agentEnvAttributes
|
||||
err = mapstructure.Decode(resource.AttributeValues, &attrs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode env attributes: %w", err)
|
||||
}
|
||||
|
||||
env := &proto.Env{
|
||||
Name: attrs.Name,
|
||||
Value: attrs.Value,
|
||||
}
|
||||
env := &proto.Env{
|
||||
Name: attrs.Name,
|
||||
Value: attrs.Value,
|
||||
}
|
||||
|
||||
envAgentLoop:
|
||||
for _, agents := range resourceAgents {
|
||||
for _, agent := range agents {
|
||||
// Find agents with the matching ID and associate them!
|
||||
if dependsOnAgent(graph, agent, attrs.AgentID, resource) {
|
||||
agent.ExtraEnvs = append(agent.ExtraEnvs, env)
|
||||
envAgentLoop:
|
||||
for _, agents := range resourceAgents {
|
||||
for _, agent := range agents {
|
||||
// Find agents with the matching ID and associate them!
|
||||
if dependsOnAgent(graph, agent, attrs.AgentID, resource) {
|
||||
agent.ExtraEnvs = append(agent.ExtraEnvs, env)
|
||||
break envAgentLoop
|
||||
}
|
||||
|
||||
for _, dc := range agent.GetDevcontainers() {
|
||||
if dependsOnDevcontainer(graph, dc, attrs.AgentID, resource) {
|
||||
dc.Envs = append(dc.Envs, env)
|
||||
break envAgentLoop
|
||||
}
|
||||
|
||||
for _, dc := range agent.GetDevcontainers() {
|
||||
if dependsOnDevcontainer(graph, dc, attrs.AgentID, resource) {
|
||||
dc.Envs = append(dc.Envs, env)
|
||||
break envAgentLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Associate scripts with agents.
|
||||
for _, resources := range tfResourcesByLabel {
|
||||
for _, resource := range resources {
|
||||
if resource.Type != "coder_script" {
|
||||
continue
|
||||
}
|
||||
var attrs agentScriptAttributes
|
||||
err = mapstructure.Decode(resource.AttributeValues, &attrs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode script attributes: %w", err)
|
||||
}
|
||||
// Sort for deterministic ordering, same as envs above.
|
||||
sortedScriptResources := sortedResourcesByType(tfResourcesByLabel, "coder_script")
|
||||
for _, resource := range sortedScriptResources {
|
||||
var attrs agentScriptAttributes
|
||||
err = mapstructure.Decode(resource.AttributeValues, &attrs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("decode script attributes: %w", err)
|
||||
}
|
||||
|
||||
script := &proto.Script{
|
||||
DisplayName: attrs.DisplayName,
|
||||
Icon: attrs.Icon,
|
||||
Script: attrs.Script,
|
||||
Cron: attrs.Cron,
|
||||
LogPath: attrs.LogPath,
|
||||
StartBlocksLogin: attrs.StartBlocksLogin,
|
||||
RunOnStart: attrs.RunOnStart,
|
||||
RunOnStop: attrs.RunOnStop,
|
||||
TimeoutSeconds: attrs.TimeoutSeconds,
|
||||
}
|
||||
script := &proto.Script{
|
||||
DisplayName: attrs.DisplayName,
|
||||
Icon: attrs.Icon,
|
||||
Script: attrs.Script,
|
||||
Cron: attrs.Cron,
|
||||
LogPath: attrs.LogPath,
|
||||
StartBlocksLogin: attrs.StartBlocksLogin,
|
||||
RunOnStart: attrs.RunOnStart,
|
||||
RunOnStop: attrs.RunOnStop,
|
||||
TimeoutSeconds: attrs.TimeoutSeconds,
|
||||
}
|
||||
|
||||
scriptAgentLoop:
|
||||
for _, agents := range resourceAgents {
|
||||
for _, agent := range agents {
|
||||
// Find agents with the matching ID and associate them!
|
||||
if dependsOnAgent(graph, agent, attrs.AgentID, resource) {
|
||||
agent.Scripts = append(agent.Scripts, script)
|
||||
scriptAgentLoop:
|
||||
for _, agents := range resourceAgents {
|
||||
for _, agent := range agents {
|
||||
// Find agents with the matching ID and associate them!
|
||||
if dependsOnAgent(graph, agent, attrs.AgentID, resource) {
|
||||
agent.Scripts = append(agent.Scripts, script)
|
||||
break scriptAgentLoop
|
||||
}
|
||||
|
||||
for _, dc := range agent.GetDevcontainers() {
|
||||
if dependsOnDevcontainer(graph, dc, attrs.AgentID, resource) {
|
||||
dc.Scripts = append(dc.Scripts, script)
|
||||
break scriptAgentLoop
|
||||
}
|
||||
|
||||
for _, dc := range agent.GetDevcontainers() {
|
||||
if dependsOnDevcontainer(graph, dc, attrs.AgentID, resource) {
|
||||
dc.Scripts = append(dc.Scripts, script)
|
||||
break scriptAgentLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1147,6 +1145,24 @@ func PtrInt32(number int) *int32 {
|
||||
return &n
|
||||
}
|
||||
|
||||
// sortedResourcesByType collects all resources of the given type from the
|
||||
// label map and returns them sorted by address. This ensures deterministic
|
||||
// iteration order when processing resources that are stored in Go maps.
|
||||
func sortedResourcesByType(tfResourcesByLabel map[string]map[string]*tfjson.StateResource, resourceType string) []*tfjson.StateResource {
|
||||
var result []*tfjson.StateResource
|
||||
for _, resources := range tfResourcesByLabel {
|
||||
for _, resource := range resources {
|
||||
if resource.Type == resourceType {
|
||||
result = append(result, resource)
|
||||
}
|
||||
}
|
||||
}
|
||||
slices.SortFunc(result, func(a, b *tfjson.StateResource) int {
|
||||
return cmp.Compare(a.Address, b.Address)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
// convertAddressToLabel returns the Terraform address without the count
|
||||
// specifier.
|
||||
// eg. "module.ec2_dev.ec2_instance.dev[0]" becomes "module.ec2_dev.ec2_instance.dev"
|
||||
|
||||
@@ -368,6 +368,49 @@ func TestConvertResources(t *testing.T) {
|
||||
Type: "coder_env",
|
||||
}},
|
||||
},
|
||||
// Verifies that when multiple coder_env resources define the
|
||||
// same key, the ordering is deterministic (sorted by Terraform
|
||||
// address). This prevents a race condition where Go map
|
||||
// iteration order could cause non-deterministic env values.
|
||||
"duplicate-env-keys": {
|
||||
resources: []*proto.Resource{{
|
||||
Name: "dev",
|
||||
Type: "null_resource",
|
||||
Agents: []*proto.Agent{{
|
||||
Name: "dev",
|
||||
OperatingSystem: "linux",
|
||||
Architecture: "amd64",
|
||||
ExtraEnvs: []*proto.Env{
|
||||
{
|
||||
Name: "PATH",
|
||||
Value: "/a/bin",
|
||||
},
|
||||
{
|
||||
Name: "PATH",
|
||||
Value: "/b/bin",
|
||||
},
|
||||
{
|
||||
Name: "UNIQUE",
|
||||
Value: "unique_value",
|
||||
},
|
||||
},
|
||||
Auth: &proto.Agent_Token{},
|
||||
ApiKeyScope: "all",
|
||||
ConnectionTimeoutSeconds: 120,
|
||||
DisplayApps: &displayApps,
|
||||
ResourcesMonitoring: &proto.ResourcesMonitoring{},
|
||||
}},
|
||||
}, {
|
||||
Name: "path_a",
|
||||
Type: "coder_env",
|
||||
}, {
|
||||
Name: "path_b",
|
||||
Type: "coder_env",
|
||||
}, {
|
||||
Name: "unique_env",
|
||||
Type: "coder_env",
|
||||
}},
|
||||
},
|
||||
"multiple-agents-multiple-monitors": {
|
||||
resources: []*proto.Resource{{
|
||||
Name: "dev",
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"Resources": [
|
||||
{
|
||||
"name": "dev",
|
||||
"type": "null_resource",
|
||||
"agents": [
|
||||
{
|
||||
"id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"name": "dev",
|
||||
"operating_system": "linux",
|
||||
"architecture": "amd64",
|
||||
"Auth": {
|
||||
"Token": "11111111-2222-3333-4444-555555555555"
|
||||
},
|
||||
"connection_timeout_seconds": 120,
|
||||
"display_apps": {
|
||||
"vscode": true,
|
||||
"web_terminal": true,
|
||||
"ssh_helper": true,
|
||||
"port_forwarding_helper": true
|
||||
},
|
||||
"extra_envs": [
|
||||
{
|
||||
"name": "PATH",
|
||||
"value": "/a/bin"
|
||||
},
|
||||
{
|
||||
"name": "PATH",
|
||||
"value": "/b/bin"
|
||||
},
|
||||
{
|
||||
"name": "UNIQUE",
|
||||
"value": "unique_value"
|
||||
}
|
||||
],
|
||||
"resources_monitoring": {},
|
||||
"api_key_scope": "all"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "path_a",
|
||||
"type": "coder_env"
|
||||
},
|
||||
{
|
||||
"name": "path_b",
|
||||
"type": "coder_env"
|
||||
},
|
||||
{
|
||||
"name": "unique_env",
|
||||
"type": "coder_env"
|
||||
}
|
||||
],
|
||||
"Parameters": [],
|
||||
"Presets": [],
|
||||
"ExternalAuthProviders": [],
|
||||
"AITasks": [],
|
||||
"HasAITasks": false,
|
||||
"HasExternalAgents": false
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"Resources": [
|
||||
{
|
||||
"name": "dev",
|
||||
"type": "null_resource",
|
||||
"agents": [
|
||||
{
|
||||
"id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"name": "dev",
|
||||
"operating_system": "linux",
|
||||
"architecture": "amd64",
|
||||
"Auth": {
|
||||
"Token": "11111111-2222-3333-4444-555555555555"
|
||||
},
|
||||
"connection_timeout_seconds": 120,
|
||||
"display_apps": {
|
||||
"vscode": true,
|
||||
"web_terminal": true,
|
||||
"ssh_helper": true,
|
||||
"port_forwarding_helper": true
|
||||
},
|
||||
"extra_envs": [
|
||||
{
|
||||
"name": "PATH",
|
||||
"value": "/a/bin"
|
||||
},
|
||||
{
|
||||
"name": "PATH",
|
||||
"value": "/b/bin"
|
||||
},
|
||||
{
|
||||
"name": "UNIQUE",
|
||||
"value": "unique_value"
|
||||
}
|
||||
],
|
||||
"resources_monitoring": {},
|
||||
"api_key_scope": "all"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "path_a",
|
||||
"type": "coder_env"
|
||||
},
|
||||
{
|
||||
"name": "path_b",
|
||||
"type": "coder_env"
|
||||
},
|
||||
{
|
||||
"name": "unique_env",
|
||||
"type": "coder_env"
|
||||
}
|
||||
],
|
||||
"Parameters": [],
|
||||
"Presets": [],
|
||||
"ExternalAuthProviders": [],
|
||||
"AITasks": [],
|
||||
"HasAITasks": false,
|
||||
"HasExternalAgents": false
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
coder = {
|
||||
source = "coder/coder"
|
||||
version = ">=2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "coder_agent" "dev" {
|
||||
os = "linux"
|
||||
arch = "amd64"
|
||||
}
|
||||
|
||||
resource "coder_env" "path_b" {
|
||||
agent_id = coder_agent.dev.id
|
||||
name = "PATH"
|
||||
value = "/b/bin"
|
||||
}
|
||||
|
||||
resource "coder_env" "path_a" {
|
||||
agent_id = coder_agent.dev.id
|
||||
name = "PATH"
|
||||
value = "/a/bin"
|
||||
}
|
||||
|
||||
resource "coder_env" "unique_env" {
|
||||
agent_id = coder_agent.dev.id
|
||||
name = "UNIQUE"
|
||||
value = "unique_value"
|
||||
}
|
||||
|
||||
resource "null_resource" "dev" {
|
||||
depends_on = [
|
||||
coder_agent.dev
|
||||
]
|
||||
}
|
||||
Generated
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
digraph {
|
||||
compound = "true"
|
||||
newrank = "true"
|
||||
subgraph "root" {
|
||||
"[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"]
|
||||
"[root] coder_env.path_a (expand)" [label = "coder_env.path_a", shape = "box"]
|
||||
"[root] coder_env.path_b (expand)" [label = "coder_env.path_b", shape = "box"]
|
||||
"[root] coder_env.unique_env (expand)" [label = "coder_env.unique_env", shape = "box"]
|
||||
"[root] null_resource.dev (expand)" [label = "null_resource.dev", shape = "box"]
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"]
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"]" [label = "provider[\"registry.terraform.io/hashicorp/null\"]", shape = "diamond"]
|
||||
"[root] coder_agent.dev (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] coder_env.path_a (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] coder_env.path_b (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] coder_env.unique_env (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] null_resource.dev (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] null_resource.dev (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_env.path_a (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_env.path_b (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_env.unique_env (expand)"
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.dev (expand)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)"
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+125
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"format_version": "1.2",
|
||||
"terraform_version": "1.11.0",
|
||||
"planned_values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "coder_agent.dev",
|
||||
"mode": "managed",
|
||||
"type": "coder_agent",
|
||||
"name": "dev",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"api_key_scope": "all",
|
||||
"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": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"init_script": "",
|
||||
"metadata": [],
|
||||
"motd_file": null,
|
||||
"order": null,
|
||||
"os": "linux",
|
||||
"resources_monitoring": [],
|
||||
"shutdown_script": null,
|
||||
"startup_script": null,
|
||||
"startup_script_behavior": "non-blocking",
|
||||
"token": "11111111-2222-3333-4444-555555555555",
|
||||
"troubleshooting_url": null
|
||||
},
|
||||
"sensitive_values": {
|
||||
"display_apps": [
|
||||
{}
|
||||
],
|
||||
"metadata": [],
|
||||
"resources_monitoring": [],
|
||||
"token": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "coder_env.path_a",
|
||||
"mode": "managed",
|
||||
"type": "coder_env",
|
||||
"name": "path_a",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"agent_id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"id": "bbbbbbbb-1111-2222-3333-444444444444",
|
||||
"name": "PATH",
|
||||
"value": "/a/bin"
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "coder_env.path_b",
|
||||
"mode": "managed",
|
||||
"type": "coder_env",
|
||||
"name": "path_b",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"agent_id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"id": "cccccccc-1111-2222-3333-444444444444",
|
||||
"name": "PATH",
|
||||
"value": "/b/bin"
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "coder_env.unique_env",
|
||||
"mode": "managed",
|
||||
"type": "coder_env",
|
||||
"name": "unique_env",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"agent_id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"id": "dddddddd-1111-2222-3333-444444444444",
|
||||
"name": "UNIQUE",
|
||||
"value": "unique_value"
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "null_resource.dev",
|
||||
"mode": "managed",
|
||||
"type": "null_resource",
|
||||
"name": "dev",
|
||||
"provider_name": "registry.terraform.io/hashicorp/null",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"id": "1234567890123456789",
|
||||
"triggers": null
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
digraph {
|
||||
compound = "true"
|
||||
newrank = "true"
|
||||
subgraph "root" {
|
||||
"[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"]
|
||||
"[root] coder_env.path_a (expand)" [label = "coder_env.path_a", shape = "box"]
|
||||
"[root] coder_env.path_b (expand)" [label = "coder_env.path_b", shape = "box"]
|
||||
"[root] coder_env.unique_env (expand)" [label = "coder_env.unique_env", shape = "box"]
|
||||
"[root] null_resource.dev (expand)" [label = "null_resource.dev", shape = "box"]
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"]" [label = "provider[\"registry.terraform.io/coder/coder\"]", shape = "diamond"]
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"]" [label = "provider[\"registry.terraform.io/hashicorp/null\"]", shape = "diamond"]
|
||||
"[root] coder_agent.dev (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]"
|
||||
"[root] coder_env.path_a (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] coder_env.path_b (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] coder_env.unique_env (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] null_resource.dev (expand)" -> "[root] coder_agent.dev (expand)"
|
||||
"[root] null_resource.dev (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_env.path_a (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_env.path_b (expand)"
|
||||
"[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_env.unique_env (expand)"
|
||||
"[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.dev (expand)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)"
|
||||
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)"
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+125
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"format_version": "1.0",
|
||||
"terraform_version": "1.11.0",
|
||||
"values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"address": "coder_agent.dev",
|
||||
"mode": "managed",
|
||||
"type": "coder_agent",
|
||||
"name": "dev",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"api_key_scope": "all",
|
||||
"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": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"init_script": "",
|
||||
"metadata": [],
|
||||
"motd_file": null,
|
||||
"order": null,
|
||||
"os": "linux",
|
||||
"resources_monitoring": [],
|
||||
"shutdown_script": null,
|
||||
"startup_script": null,
|
||||
"startup_script_behavior": "non-blocking",
|
||||
"token": "11111111-2222-3333-4444-555555555555",
|
||||
"troubleshooting_url": null
|
||||
},
|
||||
"sensitive_values": {
|
||||
"display_apps": [
|
||||
{}
|
||||
],
|
||||
"metadata": [],
|
||||
"resources_monitoring": [],
|
||||
"token": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"address": "coder_env.path_a",
|
||||
"mode": "managed",
|
||||
"type": "coder_env",
|
||||
"name": "path_a",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"agent_id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"id": "bbbbbbbb-1111-2222-3333-444444444444",
|
||||
"name": "PATH",
|
||||
"value": "/a/bin"
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "coder_env.path_b",
|
||||
"mode": "managed",
|
||||
"type": "coder_env",
|
||||
"name": "path_b",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"agent_id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"id": "cccccccc-1111-2222-3333-444444444444",
|
||||
"name": "PATH",
|
||||
"value": "/b/bin"
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "coder_env.unique_env",
|
||||
"mode": "managed",
|
||||
"type": "coder_env",
|
||||
"name": "unique_env",
|
||||
"provider_name": "registry.terraform.io/coder/coder",
|
||||
"schema_version": 1,
|
||||
"values": {
|
||||
"agent_id": "aaaaaaaa-1111-2222-3333-444444444444",
|
||||
"id": "dddddddd-1111-2222-3333-444444444444",
|
||||
"name": "UNIQUE",
|
||||
"value": "unique_value"
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "null_resource.dev",
|
||||
"mode": "managed",
|
||||
"type": "null_resource",
|
||||
"name": "dev",
|
||||
"provider_name": "registry.terraform.io/hashicorp/null",
|
||||
"schema_version": 0,
|
||||
"values": {
|
||||
"id": "1234567890123456789",
|
||||
"triggers": null
|
||||
},
|
||||
"sensitive_values": {},
|
||||
"depends_on": [
|
||||
"coder_agent.dev"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user