From 6f4047fc8bfb9e0021475c1466dba19e04762146 Mon Sep 17 00:00:00 2001 From: kylecarbs Date: Thu, 9 Jun 2022 21:26:25 +0000 Subject: [PATCH] fix: Use explicit resource order when assocating agents This cleans up agent association code to explicitly map a single agent to a single resource. This will fix #1884, and unblock a prospect from beginning a POC. --- .vscode/settings.json | 1 + provisioner/terraform/resources.go | 297 +++++++++++------- provisioner/terraform/resources_test.go | 56 +++- .../calling-module/calling-module.tfplan.dot | 6 +- .../calling-module/calling-module.tfplan.json | 74 ++++- .../calling-module/calling-module.tfstate.dot | 6 +- .../calling-module.tfstate.json | 32 +- .../testdata/calling-module/module/module.tf | 8 +- .../chaining-resources/chaining-resources.tf | 10 +- .../chaining-resources.tfplan.dot | 18 +- .../chaining-resources.tfplan.json | 40 +-- .../chaining-resources.tfstate.dot | 18 +- .../chaining-resources.tfstate.json | 26 +- .../conflicting-resources.tf | 25 ++ .../conflicting-resources.tfplan.dot | 22 ++ .../conflicting-resources.tfplan.json | 178 +++++++++++ .../conflicting-resources.tfstate.dot | 22 ++ .../conflicting-resources.tfstate.json | 62 ++++ .../instance-id/instance-id.tfstate.json | 10 +- .../multiple-agents.tfstate.json | 14 +- .../multiple-apps/multiple-apps.tfstate.json | 14 +- 21 files changed, 723 insertions(+), 216 deletions(-) create mode 100644 provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf create mode 100644 provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.dot create mode 100644 provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json create mode 100644 provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.dot create mode 100644 provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 61f0037e8e4b9..0d81d15cc32b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -63,6 +63,7 @@ "sdktrace", "Signup", "sourcemapped", + "Srcs", "stretchr", "TCGETS", "tcpip", diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 2e075a5b02a53..044ad9837445a 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -11,6 +11,28 @@ import ( "github.com/coder/coder/provisionersdk/proto" ) +// A mapping of attributes on the "coder_agent" resource. +type agentAttributes struct { + Auth string `mapstructure:"auth"` + OperatingSystem string `mapstructure:"os"` + Architecture string `mapstructure:"arch"` + Directory string `mapstructure:"dir"` + ID string `mapstructure:"id"` + Token string `mapstructure:"token"` + Env map[string]string `mapstructure:"env"` + StartupScript string `mapstructure:"startup_script"` +} + +// A mapping of attributes on the "coder_app" resource. +type agentAppAttributes struct { + AgentID string `mapstructure:"agent_id"` + Name string `mapstructure:"name"` + Icon string `mapstructure:"icon"` + URL string `mapstructure:"url"` + Command string `mapstructure:"command"` + RelativePath bool `mapstructure:"relative_path"` +} + // ConvertResources consumes Terraform state and a GraphViz representation produced by // `terraform graph` to produce resources consumable by Coder. func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Resource, error) { @@ -22,52 +44,36 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res if err != nil { return nil, xerrors.Errorf("analyze graph: %w", err) } - resourceDependencies := map[string][]string{} - for _, node := range graph.Nodes.Nodes { - label, exists := node.Attrs["label"] - if !exists { - continue - } - label = strings.Trim(label, `"`) - resourceDependencies[label] = findDependenciesWithLabels(graph, node.Name) - } resources := make([]*proto.Resource, 0) - agents := map[string]*proto.Agent{} + resourceAgents := map[string][]*proto.Agent{} - tfResources := make([]*tfjson.StateResource, 0) - var appendResources func(mod *tfjson.StateModule) - appendResources = func(mod *tfjson.StateModule) { + // Indexes Terraform resources by it's label. The label + // is what "terraform graph" uses to reference nodes. + tfResourceByLabel := map[string]*tfjson.StateResource{} + var findTerraformResources func(mod *tfjson.StateModule) + findTerraformResources = func(mod *tfjson.StateModule) { for _, module := range mod.ChildModules { - appendResources(module) + findTerraformResources(module) + } + for _, resource := range mod.Resources { + tfResourceByLabel[convertAddressToLabel(resource.Address)] = resource } - tfResources = append(tfResources, mod.Resources...) - } - appendResources(module) - - type agentAttributes struct { - Auth string `mapstructure:"auth"` - OperatingSystem string `mapstructure:"os"` - Architecture string `mapstructure:"arch"` - Directory string `mapstructure:"dir"` - ID string `mapstructure:"id"` - Token string `mapstructure:"token"` - Env map[string]string `mapstructure:"env"` - StartupScript string `mapstructure:"startup_script"` } + findTerraformResources(module) - // Store all agents inside the maps! - for _, resource := range tfResources { - if resource.Type != "coder_agent" { + // Find all agents! + for _, tfResource := range tfResourceByLabel { + if tfResource.Type != "coder_agent" { continue } var attrs agentAttributes - err = mapstructure.Decode(resource.AttributeValues, &attrs) + err = mapstructure.Decode(tfResource.AttributeValues, &attrs) if err != nil { return nil, xerrors.Errorf("decode agent attributes: %w", err) } agent := &proto.Agent{ - Name: resource.Name, + Name: tfResource.Name, Id: attrs.ID, Env: attrs.Env, StartupScript: attrs.StartupScript, @@ -81,14 +87,56 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res Token: attrs.Token, } default: + // If token authentication isn't specified, + // assume instance auth. It's our only other + // authentication type! agent.Auth = &proto.Agent_InstanceId{} } - agents[convertAddressToLabel(resource.Address)] = agent + // The label is used to find the graph node! + agentLabel := convertAddressToLabel(tfResource.Address) + + var agentNode *gographviz.Node + for _, node := range graph.Nodes.Lookup { + // The node attributes surround the label with quotes. + if strings.Trim(node.Attrs["label"], `"`) != agentLabel { + continue + } + agentNode = node + break + } + if agentNode == nil { + return nil, xerrors.Errorf("couldn't find node on graph: %q", agentLabel) + } + + var agentResource *graphResource + for _, resource := range findResourcesUpGraph(graph, tfResourceByLabel, agentNode.Name, 0) { + if agentResource == nil { + // Default to the first resource because we have nothing to compare! + agentResource = resource + continue + } + if resource.Depth < agentResource.Depth { + // There's a closer resource! + agentResource = resource + continue + } + if resource.Depth == agentResource.Depth && resource.Label < agentResource.Label { + agentResource = resource + continue + } + } + + agents, exists := resourceAgents[agentResource.Label] + if !exists { + agents = make([]*proto.Agent, 0) + } + agents = append(agents, agent) + resourceAgents[agentResource.Label] = agents } // Manually associate agents with instance IDs. - for _, resource := range tfResources { + for _, resource := range tfResourceByLabel { if resource.Type != "coder_agent_instance" { continue } @@ -109,31 +157,25 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res continue } - for _, agent := range agents { - if agent.Id != agentID { - continue + for _, agents := range resourceAgents { + for _, agent := range agents { + if agent.Id != agentID { + continue + } + agent.Auth = &proto.Agent_InstanceId{ + InstanceId: instanceID, + } + break } - agent.Auth = &proto.Agent_InstanceId{ - InstanceId: instanceID, - } - break } } - type appAttributes struct { - AgentID string `mapstructure:"agent_id"` - Name string `mapstructure:"name"` - Icon string `mapstructure:"icon"` - URL string `mapstructure:"url"` - Command string `mapstructure:"command"` - RelativePath bool `mapstructure:"relative_path"` - } // Associate Apps with agents. - for _, resource := range tfResources { + for _, resource := range tfResourceByLabel { if resource.Type != "coder_app" { continue } - var attrs appAttributes + var attrs agentAppAttributes err = mapstructure.Decode(resource.AttributeValues, &attrs) if err != nil { return nil, xerrors.Errorf("decode app attributes: %w", err) @@ -142,58 +184,34 @@ func ConvertResources(module *tfjson.StateModule, rawGraph string) ([]*proto.Res // Default to the resource name if none is set! attrs.Name = resource.Name } - for _, agent := range agents { - if agent.Id != attrs.AgentID { - continue + for _, agents := range resourceAgents { + for _, agent := range agents { + // Find agents with the matching ID and associate them! + if agent.Id != attrs.AgentID { + continue + } + agent.Apps = append(agent.Apps, &proto.App{ + Name: attrs.Name, + Command: attrs.Command, + Url: attrs.URL, + Icon: attrs.Icon, + RelativePath: attrs.RelativePath, + }) } - agent.Apps = append(agent.Apps, &proto.App{ - Name: attrs.Name, - Command: attrs.Command, - Url: attrs.URL, - Icon: attrs.Icon, - RelativePath: attrs.RelativePath, - }) } } - for _, resource := range tfResources { + for _, resource := range tfResourceByLabel { if resource.Mode == tfjson.DataResourceMode { continue } if resource.Type == "coder_agent" || resource.Type == "coder_agent_instance" || resource.Type == "coder_app" { continue } - agents := findAgents(resourceDependencies, agents, convertAddressToLabel(resource.Address)) - for _, agent := range agents { - // Didn't use instance identity. - if agent.GetToken() != "" { - continue - } - // These resource types are for automatically associating an instance ID - // with an agent for authentication. - key, isValid := map[string]string{ - "google_compute_instance": "instance_id", - "aws_instance": "id", - "azurerm_linux_virtual_machine": "id", - "azurerm_windows_virtual_machine": "id", - }[resource.Type] - if !isValid { - // The resource type doesn't support - // automatically setting the instance ID. - continue - } - instanceIDRaw, valid := resource.AttributeValues[key] - if !valid { - continue - } - instanceID, valid := instanceIDRaw.(string) - if !valid { - continue - } - agent.Auth = &proto.Agent_InstanceId{ - InstanceId: instanceID, - } + agents, exists := resourceAgents[convertAddressToLabel(resource.Address)] + if exists { + applyAutomaticInstanceID(resource, agents) } resources = append(resources, &proto.Resource{ @@ -212,46 +230,83 @@ func convertAddressToLabel(address string) string { return strings.Split(address, "[")[0] } -// findAgents recursively searches through resource dependencies -// to find associated agents. Nested is required for indirect -// dependency matching. -func findAgents(resourceDependencies map[string][]string, agents map[string]*proto.Agent, resourceLabel string) []*proto.Agent { - resourceNode, exists := resourceDependencies[resourceLabel] - if !exists { - return []*proto.Agent{} +type graphResource struct { + Label string + Depth uint +} + +// applyAutomaticInstanceID checks if the resource is one of a set of *magical* IDs +// that automatically index their identifier for automatic authentication. +func applyAutomaticInstanceID(resource *tfjson.StateResource, agents []*proto.Agent) { + // These resource types are for automatically associating an instance ID + // with an agent for authentication. + key, isValid := map[string]string{ + "google_compute_instance": "instance_id", + "aws_instance": "id", + "azurerm_linux_virtual_machine": "id", + "azurerm_windows_virtual_machine": "id", + }[resource.Type] + if !isValid { + return } - // Associate resources that depend on an agent. - resourceAgents := make([]*proto.Agent, 0) - for _, dep := range resourceNode { - var has bool - agent, has := agents[dep] - if !has { - resourceAgents = append(resourceAgents, findAgents(resourceDependencies, agents, dep)...) + + // The resource type doesn't support + // automatically setting the instance ID. + instanceIDRaw, isValid := resource.AttributeValues[key] + if !isValid { + return + } + instanceID, isValid := instanceIDRaw.(string) + if !isValid { + return + } + for _, agent := range agents { + // Didn't use instance identity. + if agent.GetToken() != "" { continue } - // An agent must be deleted after being assigned so it isn't referenced twice. - delete(agents, dep) - resourceAgents = append(resourceAgents, agent) + if agent.GetInstanceId() != "" { + // If an instance ID is manually specified, do not override! + continue + } + + agent.Auth = &proto.Agent_InstanceId{ + InstanceId: instanceID, + } } - return resourceAgents } -// findDependenciesWithLabels recursively finds nodes with labels (resource and data nodes) -// to build a dependency tree. -func findDependenciesWithLabels(graph *gographviz.Graph, nodeName string) []string { - dependencies := make([]string, 0) - for destination := range graph.Edges.SrcToDsts[nodeName] { - dependencyNode, exists := graph.Nodes.Lookup[destination] +// findResourcesUpGraph traverses upwards in a graph until a resource is found, +// then it stores the depth it was found at, and continues working up the tree. +func findResourcesUpGraph(graph *gographviz.Graph, tfResourceByLabel map[string]*tfjson.StateResource, nodeName string, currentDepth uint) []*graphResource { + graphResources := make([]*graphResource, 0) + for destination := range graph.Edges.DstToSrcs[nodeName] { + destinationNode := graph.Nodes.Lookup[destination] + // Work our way up the tree! + graphResources = append(graphResources, findResourcesUpGraph(graph, tfResourceByLabel, destinationNode.Name, currentDepth+1)...) + + destinationLabel, exists := destinationNode.Attrs["label"] if !exists { continue } - label, exists := dependencyNode.Attrs["label"] + destinationLabel = strings.Trim(destinationLabel, `"`) + resource, exists := tfResourceByLabel[destinationLabel] if !exists { - dependencies = append(dependencies, findDependenciesWithLabels(graph, dependencyNode.Name)...) continue } - label = strings.Trim(label, `"`) - dependencies = append(dependencies, label) + // Data sources cannot be associated with agents for now! + if resource.Mode != tfjson.ManagedResourceMode { + continue + } + // Don't associate Coder resources with other Coder resources! + if strings.HasPrefix(resource.Type, "coder_") { + continue + } + graphResources = append(graphResources, &graphResource{ + Label: destinationLabel, + Depth: currentDepth, + }) } - return dependencies + + return graphResources } diff --git a/provisioner/terraform/resources_test.go b/provisioner/terraform/resources_test.go index 03386557151e6..e7d9517a22120 100644 --- a/provisioner/terraform/resources_test.go +++ b/provisioner/terraform/resources_test.go @@ -22,11 +22,29 @@ func TestConvertResources(t *testing.T) { _, filename, _, _ := runtime.Caller(0) // nolint:paralleltest for folderName, expected := range map[string][]*proto.Resource{ + // When a resource depends on another, the shortest route + // to a resource should always be chosen for the agent. "chaining-resources": {{ + Name: "a", + Type: "null_resource", + }, { + Name: "b", + Type: "null_resource", + Agents: []*proto.Agent{{ + Name: "dev", + OperatingSystem: "linux", + Architecture: "amd64", + Auth: &proto.Agent_Token{}, + }}, + }}, + // This can happen when resources hierarchically conflict. + // When multiple resources exist at the same level, the first + // listed in state will be chosen. + "conflicting-resources": {{ Name: "first", Type: "null_resource", Agents: []*proto.Agent{{ - Name: "dev1", + Name: "dev", OperatingSystem: "linux", Architecture: "amd64", Auth: &proto.Agent_Token{}, @@ -35,6 +53,7 @@ func TestConvertResources(t *testing.T) { Name: "second", Type: "null_resource", }}, + // Ensures the instance ID authentication type surfaces. "instance-id": {{ Name: "dev", Type: "null_resource", @@ -45,6 +64,8 @@ func TestConvertResources(t *testing.T) { Auth: &proto.Agent_InstanceId{}, }}, }}, + // Ensures that calls to resources through modules work + // as expected. "calling-module": {{ Name: "example", Type: "null_resource", @@ -55,6 +76,8 @@ func TestConvertResources(t *testing.T) { Auth: &proto.Agent_Token{}, }}, }}, + // Ensures the attachment of multiple agents to a single + // resource is successful. "multiple-agents": {{ Name: "dev", Type: "null_resource", @@ -75,6 +98,7 @@ func TestConvertResources(t *testing.T) { Auth: &proto.Agent_Token{}, }}, }}, + // Ensures multiple applications can be set for a single agent. "multiple-apps": {{ Name: "dev", Type: "null_resource", @@ -109,11 +133,7 @@ func TestConvertResources(t *testing.T) { resources, err := terraform.ConvertResources(tfPlan.PlannedValues.RootModule, string(tfPlanGraph)) require.NoError(t, err) - for _, resource := range resources { - sort.Slice(resource.Agents, func(i, j int) bool { - return resource.Agents[i].Name < resource.Agents[j].Name - }) - } + sortResources(resources) resourcesWant, err := json.Marshal(expected) require.NoError(t, err) resourcesGot, err := json.Marshal(resources) @@ -132,10 +152,8 @@ func TestConvertResources(t *testing.T) { resources, err := terraform.ConvertResources(tfState.Values.RootModule, string(tfStateGraph)) require.NoError(t, err) + sortResources(resources) for _, resource := range resources { - sort.Slice(resource.Agents, func(i, j int) bool { - return resource.Agents[i].Name < resource.Agents[j].Name - }) for _, agent := range resource.Agents { agent.Id = "" if agent.GetToken() != "" { @@ -191,6 +209,7 @@ func TestInstanceIDAssociation(t *testing.T) { Address: "coder_agent.dev", Type: "coder_agent", Name: "dev", + Mode: tfjson.ManagedResourceMode, AttributeValues: map[string]interface{}{ "arch": "amd64", "auth": tc.Auth, @@ -199,6 +218,7 @@ func TestInstanceIDAssociation(t *testing.T) { Address: tc.ResourceType + ".dev", Type: tc.ResourceType, Name: "dev", + Mode: tfjson.ManagedResourceMode, DependsOn: []string{"coder_agent.dev"}, AttributeValues: map[string]interface{}{ tc.InstanceIDKey: instanceID, @@ -222,3 +242,21 @@ func TestInstanceIDAssociation(t *testing.T) { }) } } + +// sortResource ensures resources appear in a consistent ordering +// to prevent tests from flaking. +func sortResources(resources []*proto.Resource) { + sort.Slice(resources, func(i, j int) bool { + return resources[i].Name < resources[j].Name + }) + for _, resource := range resources { + for _, agent := range resource.Agents { + sort.Slice(agent.Apps, func(i, j int) bool { + return agent.Apps[i].Name < agent.Apps[j].Name + }) + } + sort.Slice(resource.Agents, func(i, j int) bool { + return resource.Agents[i].Name < resource.Agents[j].Name + }) + } +} diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.dot b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.dot index 0d5447f4bb153..4cdf10b11a0b4 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.dot +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.dot @@ -3,13 +3,15 @@ digraph { newrank = "true" subgraph "root" { "[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"] + "[root] module.module.data.null_data_source.script (expand)" [label = "module.module.data.null_data_source.script", shape = "box"] "[root] module.module.null_resource.example (expand)" [label = "module.module.null_resource.example", 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] module.module (close)" -> "[root] module.module.null_resource.example (expand)" - "[root] module.module.null_resource.example (expand)" -> "[root] module.module.var.script (expand)" - "[root] module.module.null_resource.example (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] module.module.data.null_data_source.script (expand)" -> "[root] module.module.var.script (expand)" + "[root] module.module.data.null_data_source.script (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] module.module.null_resource.example (expand)" -> "[root] module.module.data.null_data_source.script (expand)" "[root] module.module.var.script (expand)" -> "[root] coder_agent.dev (expand)" "[root] module.module.var.script (expand)" -> "[root] module.module (expand)" "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)" diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json index 57b0ec2bbdaac..c703e64f5d1d2 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfplan.json @@ -25,6 +25,21 @@ "child_modules": [ { "resources": [ + { + "address": "module.module.data.null_data_source.script", + "mode": "data", + "type": "null_data_source", + "name": "script", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "inputs": {} + }, + "sensitive_values": { + "inputs": {}, + "outputs": {} + } + }, { "address": "module.module.null_resource.example", "mode": "managed", @@ -72,6 +87,38 @@ "after_sensitive": {} } }, + { + "address": "module.module.data.null_data_source.script", + "module_address": "module.module", + "mode": "data", + "type": "null_data_source", + "name": "script", + "provider_name": "registry.terraform.io/hashicorp/null", + "change": { + "actions": [ + "read" + ], + "before": null, + "after": { + "inputs": {} + }, + "after_unknown": { + "has_computed_default": true, + "id": true, + "inputs": { + "script": true + }, + "outputs": true, + "random": true + }, + "before_sensitive": false, + "after_sensitive": { + "inputs": {}, + "outputs": {} + } + }, + "action_reason": "read_because_config_unknown" + }, { "address": "module.module.null_resource.example", "module_address": "module.module", @@ -148,8 +195,23 @@ "provider_config_key": "module.module:null", "schema_version": 0, "depends_on": [ - "var.script" + "data.null_data_source.script" ] + }, + { + "address": "data.null_data_source.script", + "mode": "data", + "type": "null_data_source", + "name": "script", + "provider_config_key": "module.module:null", + "expressions": { + "inputs": { + "references": [ + "var.script" + ] + } + }, + "schema_version": 0 } ], "variables": { @@ -159,5 +221,13 @@ } } } - } + }, + "relevant_attributes": [ + { + "resource": "coder_agent.dev", + "attribute": [ + "init_script" + ] + } + ] } diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.dot b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.dot index 0d5447f4bb153..4cdf10b11a0b4 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.dot +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.dot @@ -3,13 +3,15 @@ digraph { newrank = "true" subgraph "root" { "[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"] + "[root] module.module.data.null_data_source.script (expand)" [label = "module.module.data.null_data_source.script", shape = "box"] "[root] module.module.null_resource.example (expand)" [label = "module.module.null_resource.example", 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] module.module (close)" -> "[root] module.module.null_resource.example (expand)" - "[root] module.module.null_resource.example (expand)" -> "[root] module.module.var.script (expand)" - "[root] module.module.null_resource.example (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] module.module.data.null_data_source.script (expand)" -> "[root] module.module.var.script (expand)" + "[root] module.module.data.null_data_source.script (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] module.module.null_resource.example (expand)" -> "[root] module.module.data.null_data_source.script (expand)" "[root] module.module.var.script (expand)" -> "[root] coder_agent.dev (expand)" "[root] module.module.var.script (expand)" -> "[root] module.module (expand)" "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)" diff --git a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json index d3c18630106e4..5efed1544f880 100644 --- a/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json +++ b/provisioner/terraform/testdata/calling-module/calling-module.tfstate.json @@ -16,11 +16,11 @@ "auth": "token", "dir": null, "env": null, - "id": "0f0b7be8-9d82-4b01-b5e5-88279ae4f977", + "id": "66fed4b4-2246-4c0f-8e55-74e109ee0603", "init_script": "", "os": "linux", "startup_script": null, - "token": "0144998d-4154-495a-902b-0cece2800d76" + "token": "c7f7d527-3eab-4f77-8c0f-05f543bce5c1" }, "sensitive_values": {} } @@ -28,6 +28,29 @@ "child_modules": [ { "resources": [ + { + "address": "module.module.data.null_data_source.script", + "mode": "data", + "type": "null_data_source", + "name": "script", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "has_computed_default": "default", + "id": "static", + "inputs": { + "script": "" + }, + "outputs": { + "script": "" + }, + "random": "2465369318401710566" + }, + "sensitive_values": { + "inputs": {}, + "outputs": {} + } + }, { "address": "module.module.null_resource.example", "mode": "managed", @@ -36,12 +59,13 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "4090647596312392999", + "id": "354396519773748320", "triggers": null }, "sensitive_values": {}, "depends_on": [ - "coder_agent.dev" + "coder_agent.dev", + "module.module.data.null_data_source.script" ] } ], diff --git a/provisioner/terraform/testdata/calling-module/module/module.tf b/provisioner/terraform/testdata/calling-module/module/module.tf index deb3f71f5a3cf..483b1511df10b 100644 --- a/provisioner/terraform/testdata/calling-module/module/module.tf +++ b/provisioner/terraform/testdata/calling-module/module/module.tf @@ -2,8 +2,14 @@ variable "script" { type = string } +data "null_data_source" "script" { + inputs = { + script = var.script + } +} + resource "null_resource" "example" { depends_on = [ - var.script + data.null_data_source.script ] } diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf index cc5a43218beac..7125d9d89f089 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tf @@ -7,19 +7,19 @@ terraform { } } -resource "coder_agent" "dev1" { +resource "coder_agent" "dev" { os = "linux" arch = "amd64" } -resource "null_resource" "first" { +resource "null_resource" "b" { depends_on = [ - coder_agent.dev1 + coder_agent.dev ] } -resource "null_resource" "second" { +resource "null_resource" "a" { depends_on = [ - null_resource.first + null_resource.b ] } diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.dot b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.dot index b590846e3828e..aa21b626e6a82 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.dot +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.dot @@ -2,17 +2,17 @@ digraph { compound = "true" newrank = "true" subgraph "root" { - "[root] coder_agent.dev1 (expand)" [label = "coder_agent.dev1", shape = "box"] - "[root] null_resource.first (expand)" [label = "null_resource.first", shape = "box"] - "[root] null_resource.second (expand)" [label = "null_resource.second", shape = "box"] + "[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"] + "[root] null_resource.a (expand)" [label = "null_resource.a", shape = "box"] + "[root] null_resource.b (expand)" [label = "null_resource.b", 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.dev1 (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" - "[root] null_resource.first (expand)" -> "[root] coder_agent.dev1 (expand)" - "[root] null_resource.first (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" - "[root] null_resource.second (expand)" -> "[root] null_resource.first (expand)" - "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev1 (expand)" - "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.second (expand)" + "[root] coder_agent.dev (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] null_resource.a (expand)" -> "[root] null_resource.b (expand)" + "[root] null_resource.b (expand)" -> "[root] coder_agent.dev (expand)" + "[root] null_resource.b (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)" + "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.a (expand)" "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" "[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" } diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json index 9e338c184cc9f..92e9849f56ccb 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfplan.json @@ -5,10 +5,10 @@ "root_module": { "resources": [ { - "address": "coder_agent.dev1", + "address": "coder_agent.dev", "mode": "managed", "type": "coder_agent", - "name": "dev1", + "name": "dev", "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { @@ -22,10 +22,10 @@ "sensitive_values": {} }, { - "address": "null_resource.first", + "address": "null_resource.a", "mode": "managed", "type": "null_resource", - "name": "first", + "name": "a", "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { @@ -34,10 +34,10 @@ "sensitive_values": {} }, { - "address": "null_resource.second", + "address": "null_resource.b", "mode": "managed", "type": "null_resource", - "name": "second", + "name": "b", "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { @@ -50,10 +50,10 @@ }, "resource_changes": [ { - "address": "coder_agent.dev1", + "address": "coder_agent.dev", "mode": "managed", "type": "coder_agent", - "name": "dev1", + "name": "dev", "provider_name": "registry.terraform.io/coder/coder", "change": { "actions": [ @@ -78,10 +78,10 @@ } }, { - "address": "null_resource.first", + "address": "null_resource.a", "mode": "managed", "type": "null_resource", - "name": "first", + "name": "a", "provider_name": "registry.terraform.io/hashicorp/null", "change": { "actions": [ @@ -99,10 +99,10 @@ } }, { - "address": "null_resource.second", + "address": "null_resource.b", "mode": "managed", "type": "null_resource", - "name": "second", + "name": "b", "provider_name": "registry.terraform.io/hashicorp/null", "change": { "actions": [ @@ -135,10 +135,10 @@ "root_module": { "resources": [ { - "address": "coder_agent.dev1", + "address": "coder_agent.dev", "mode": "managed", "type": "coder_agent", - "name": "dev1", + "name": "dev", "provider_config_key": "coder", "expressions": { "arch": { @@ -151,25 +151,25 @@ "schema_version": 0 }, { - "address": "null_resource.first", + "address": "null_resource.a", "mode": "managed", "type": "null_resource", - "name": "first", + "name": "a", "provider_config_key": "null", "schema_version": 0, "depends_on": [ - "coder_agent.dev1" + "null_resource.b" ] }, { - "address": "null_resource.second", + "address": "null_resource.b", "mode": "managed", "type": "null_resource", - "name": "second", + "name": "b", "provider_config_key": "null", "schema_version": 0, "depends_on": [ - "null_resource.first" + "coder_agent.dev" ] } ] diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.dot b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.dot index b590846e3828e..aa21b626e6a82 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.dot +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.dot @@ -2,17 +2,17 @@ digraph { compound = "true" newrank = "true" subgraph "root" { - "[root] coder_agent.dev1 (expand)" [label = "coder_agent.dev1", shape = "box"] - "[root] null_resource.first (expand)" [label = "null_resource.first", shape = "box"] - "[root] null_resource.second (expand)" [label = "null_resource.second", shape = "box"] + "[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"] + "[root] null_resource.a (expand)" [label = "null_resource.a", shape = "box"] + "[root] null_resource.b (expand)" [label = "null_resource.b", 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.dev1 (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" - "[root] null_resource.first (expand)" -> "[root] coder_agent.dev1 (expand)" - "[root] null_resource.first (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" - "[root] null_resource.second (expand)" -> "[root] null_resource.first (expand)" - "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev1 (expand)" - "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.second (expand)" + "[root] coder_agent.dev (expand)" -> "[root] provider[\"registry.terraform.io/coder/coder\"]" + "[root] null_resource.a (expand)" -> "[root] null_resource.b (expand)" + "[root] null_resource.b (expand)" -> "[root] coder_agent.dev (expand)" + "[root] null_resource.b (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)" + "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.a (expand)" "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" "[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" } diff --git a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json index 06e6bd12ab28d..d3d8e99a95e6f 100644 --- a/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json +++ b/provisioner/terraform/testdata/chaining-resources/chaining-resources.tfstate.json @@ -5,10 +5,10 @@ "root_module": { "resources": [ { - "address": "coder_agent.dev1", + "address": "coder_agent.dev", "mode": "managed", "type": "coder_agent", - "name": "dev1", + "name": "dev", "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { @@ -16,45 +16,45 @@ "auth": "token", "dir": null, "env": null, - "id": "299427de-bf0c-45a9-9780-97b5c7ea83e7", + "id": "44e31a74-646f-4f29-a979-ff0da7108ed6", "init_script": "", "os": "linux", "startup_script": null, - "token": "c470ea31-7bb4-49f0-af5a-c1d8ad3f2e1c" + "token": "3c011212-912c-45f5-8cdb-84b7e03a8d44" }, "sensitive_values": {} }, { - "address": "null_resource.first", + "address": "null_resource.a", "mode": "managed", "type": "null_resource", - "name": "first", + "name": "a", "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "743088824302893232", + "id": "5747685929405905376", "triggers": null }, "sensitive_values": {}, "depends_on": [ - "coder_agent.dev1" + "coder_agent.dev", + "null_resource.b" ] }, { - "address": "null_resource.second", + "address": "null_resource.b", "mode": "managed", "type": "null_resource", - "name": "second", + "name": "b", "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "661153862134717768", + "id": "4234681175686342228", "triggers": null }, "sensitive_values": {}, "depends_on": [ - "coder_agent.dev1", - "null_resource.first" + "coder_agent.dev" ] } ] diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf new file mode 100644 index 0000000000000..9da5aa64e6384 --- /dev/null +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tf @@ -0,0 +1,25 @@ +terraform { + required_providers { + coder = { + source = "coder/coder" + version = "0.4.2" + } + } +} + +resource "coder_agent" "dev" { + os = "linux" + arch = "amd64" +} + +resource "null_resource" "first" { + depends_on = [ + coder_agent.dev + ] +} + +resource "null_resource" "second" { + depends_on = [ + coder_agent.dev + ] +} diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.dot b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.dot new file mode 100644 index 0000000000000..4e5efe7551100 --- /dev/null +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.dot @@ -0,0 +1,22 @@ +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"] + "[root] null_resource.first (expand)" [label = "null_resource.first", shape = "box"] + "[root] null_resource.second (expand)" [label = "null_resource.second", 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] null_resource.first (expand)" -> "[root] coder_agent.dev (expand)" + "[root] null_resource.first (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] null_resource.second (expand)" -> "[root] coder_agent.dev (expand)" + "[root] null_resource.second (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)" + "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.first (expand)" + "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.second (expand)" + "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" + "[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" + } +} + diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json new file mode 100644 index 0000000000000..20b9740114f34 --- /dev/null +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfplan.json @@ -0,0 +1,178 @@ +{ + "format_version": "1.1", + "terraform_version": "1.2.2", + "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": 0, + "values": { + "arch": "amd64", + "auth": "token", + "dir": null, + "env": null, + "os": "linux", + "startup_script": null + }, + "sensitive_values": {} + }, + { + "address": "null_resource.first", + "mode": "managed", + "type": "null_resource", + "name": "first", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "triggers": null + }, + "sensitive_values": {} + }, + { + "address": "null_resource.second", + "mode": "managed", + "type": "null_resource", + "name": "second", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "triggers": null + }, + "sensitive_values": {} + } + ] + } + }, + "resource_changes": [ + { + "address": "coder_agent.dev", + "mode": "managed", + "type": "coder_agent", + "name": "dev", + "provider_name": "registry.terraform.io/coder/coder", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "arch": "amd64", + "auth": "token", + "dir": null, + "env": null, + "os": "linux", + "startup_script": null + }, + "after_unknown": { + "id": true, + "init_script": true, + "token": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "null_resource.first", + "mode": "managed", + "type": "null_resource", + "name": "first", + "provider_name": "registry.terraform.io/hashicorp/null", + "change": { + "actions": [ + "create" + ], + "before": null, + "after": { + "triggers": null + }, + "after_unknown": { + "id": true + }, + "before_sensitive": false, + "after_sensitive": {} + } + }, + { + "address": "null_resource.second", + "mode": "managed", + "type": "null_resource", + "name": "second", + "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": "0.4.2" + }, + "null": { + "name": "null", + "full_name": "registry.terraform.io/hashicorp/null" + } + }, + "root_module": { + "resources": [ + { + "address": "coder_agent.dev", + "mode": "managed", + "type": "coder_agent", + "name": "dev", + "provider_config_key": "coder", + "expressions": { + "arch": { + "constant_value": "amd64" + }, + "os": { + "constant_value": "linux" + } + }, + "schema_version": 0 + }, + { + "address": "null_resource.first", + "mode": "managed", + "type": "null_resource", + "name": "first", + "provider_config_key": "null", + "schema_version": 0, + "depends_on": [ + "coder_agent.dev" + ] + }, + { + "address": "null_resource.second", + "mode": "managed", + "type": "null_resource", + "name": "second", + "provider_config_key": "null", + "schema_version": 0, + "depends_on": [ + "coder_agent.dev" + ] + } + ] + } + } +} diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.dot b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.dot new file mode 100644 index 0000000000000..4e5efe7551100 --- /dev/null +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.dot @@ -0,0 +1,22 @@ +digraph { + compound = "true" + newrank = "true" + subgraph "root" { + "[root] coder_agent.dev (expand)" [label = "coder_agent.dev", shape = "box"] + "[root] null_resource.first (expand)" [label = "null_resource.first", shape = "box"] + "[root] null_resource.second (expand)" [label = "null_resource.second", 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] null_resource.first (expand)" -> "[root] coder_agent.dev (expand)" + "[root] null_resource.first (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] null_resource.second (expand)" -> "[root] coder_agent.dev (expand)" + "[root] null_resource.second (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"]" + "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" -> "[root] coder_agent.dev (expand)" + "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.first (expand)" + "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" -> "[root] null_resource.second (expand)" + "[root] root" -> "[root] provider[\"registry.terraform.io/coder/coder\"] (close)" + "[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/null\"] (close)" + } +} + diff --git a/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json new file mode 100644 index 0000000000000..4bed6de18d3b5 --- /dev/null +++ b/provisioner/terraform/testdata/conflicting-resources/conflicting-resources.tfstate.json @@ -0,0 +1,62 @@ +{ + "format_version": "1.0", + "terraform_version": "1.2.2", + "values": { + "root_module": { + "resources": [ + { + "address": "coder_agent.dev", + "mode": "managed", + "type": "coder_agent", + "name": "dev", + "provider_name": "registry.terraform.io/coder/coder", + "schema_version": 0, + "values": { + "arch": "amd64", + "auth": "token", + "dir": null, + "env": null, + "id": "99a85fe5-719f-4d20-8dd9-d02e7d477c45", + "init_script": "", + "os": "linux", + "startup_script": null, + "token": "7bdf3592-b3d0-42f8-8e81-132903f28614" + }, + "sensitive_values": {} + }, + { + "address": "null_resource.first", + "mode": "managed", + "type": "null_resource", + "name": "first", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "id": "5367760563120181345", + "triggers": null + }, + "sensitive_values": {}, + "depends_on": [ + "coder_agent.dev" + ] + }, + { + "address": "null_resource.second", + "mode": "managed", + "type": "null_resource", + "name": "second", + "provider_name": "registry.terraform.io/hashicorp/null", + "schema_version": 0, + "values": { + "id": "3224902069148001434", + "triggers": null + }, + "sensitive_values": {}, + "depends_on": [ + "coder_agent.dev" + ] + } + ] + } + } +} diff --git a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json index bd86ce2abf5d5..811786b6f40dd 100644 --- a/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json +++ b/provisioner/terraform/testdata/instance-id/instance-id.tfstate.json @@ -16,11 +16,11 @@ "auth": "google-instance-identity", "dir": null, "env": null, - "id": "a72e01b2-71e9-4498-943f-d1a117c696a0", + "id": "af919173-b148-4852-9552-453c5665efc4", "init_script": "", "os": "linux", "startup_script": null, - "token": "553aedb8-98b2-4f4d-87aa-428ba11afd5c" + "token": "06bcca4d-b37f-4f82-8fcb-f3c00387748a" }, "sensitive_values": {} }, @@ -32,8 +32,8 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { - "agent_id": "a72e01b2-71e9-4498-943f-d1a117c696a0", - "id": "c1552a99-782e-4d2b-a5b6-638b3f7297e4", + "agent_id": "af919173-b148-4852-9552-453c5665efc4", + "id": "f90a6c0f-11c1-4737-982f-e54590c46cea", "instance_id": "example" }, "sensitive_values": {}, @@ -49,7 +49,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2578813038449197470", + "id": "4993832153889617160", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json index 1ccdbafa45afe..4cf226531c76a 100644 --- a/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json +++ b/provisioner/terraform/testdata/multiple-agents/multiple-agents.tfstate.json @@ -16,11 +16,11 @@ "auth": "token", "dir": null, "env": null, - "id": "04cb673b-c7b5-47c9-a445-f0f7e11f2696", + "id": "521a6bee-1193-468f-bbe9-4a25a870a9f0", "init_script": "", "os": "linux", "startup_script": null, - "token": "95e9607b-1ff3-4a35-8ee8-c61248fb5642" + "token": "ee0452e2-7efe-4a84-9407-e871c7c4f4c4" }, "sensitive_values": {} }, @@ -36,11 +36,11 @@ "auth": "token", "dir": null, "env": null, - "id": "d97044e4-ce09-4eaf-904e-cd9575f07122", + "id": "f1c2eb3a-2303-4499-8cfc-5a63f5d57def", "init_script": "", "os": "darwin", "startup_script": null, - "token": "dc49231a-57e1-4a21-bb74-ae34f753d7bf" + "token": "15ea44b7-acd7-41d5-98a3-93ac23bd2b84" }, "sensitive_values": {} }, @@ -56,11 +56,11 @@ "auth": "token", "dir": null, "env": null, - "id": "8b03bbd1-bd6a-4a54-b083-9d773c91de54", + "id": "445a229e-6886-46ba-9947-94d39b90b941", "init_script": "", "os": "windows", "startup_script": null, - "token": "4b91ef3f-cada-4b27-9872-df2c5a47e24a" + "token": "26a999c8-d281-46da-a296-15318d4c0998" }, "sensitive_values": {} }, @@ -72,7 +72,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "8472507680226374958", + "id": "6903043049471472110", "triggers": null }, "sensitive_values": {}, diff --git a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json index 678926d95cd8e..1c290719cac8b 100644 --- a/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json +++ b/provisioner/terraform/testdata/multiple-apps/multiple-apps.tfstate.json @@ -16,11 +16,11 @@ "auth": "token", "dir": null, "env": null, - "id": "0ab1ceca-8ce9-4f02-97bb-9f4087739ce9", + "id": "d613fec9-933b-490f-97c7-7e6527e02a91", "init_script": "", "os": "linux", "startup_script": null, - "token": "3a5de99e-5b10-459c-a3d0-0fb0fdf1f43b" + "token": "564c308a-5d9e-42f9-b2a5-da28d3c04a90" }, "sensitive_values": {} }, @@ -32,10 +32,10 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { - "agent_id": "0ab1ceca-8ce9-4f02-97bb-9f4087739ce9", + "agent_id": "d613fec9-933b-490f-97c7-7e6527e02a91", "command": null, "icon": null, - "id": "5b6a8a53-0368-4313-89cd-65dc2d9daa2d", + "id": "2b92ebdb-1169-4247-b039-87aeaeaf55b3", "name": null, "relative_path": null, "url": null @@ -53,10 +53,10 @@ "provider_name": "registry.terraform.io/coder/coder", "schema_version": 0, "values": { - "agent_id": "0ab1ceca-8ce9-4f02-97bb-9f4087739ce9", + "agent_id": "d613fec9-933b-490f-97c7-7e6527e02a91", "command": null, "icon": null, - "id": "2b421408-9538-422a-8254-df4b629d0a34", + "id": "80eedec0-8816-4c8d-96b7-3aa3d5b5cef8", "name": null, "relative_path": null, "url": null @@ -74,7 +74,7 @@ "provider_name": "registry.terraform.io/hashicorp/null", "schema_version": 0, "values": { - "id": "2309999552249167252", + "id": "3551148082877575423", "triggers": null }, "sensitive_values": {},