TritonDataCenter / terraform-provider-triton

Terraform Joyent Triton provider
https://www.terraform.io/docs/providers/triton/
Mozilla Public License 2.0
15 stars 24 forks source link

Updating CNS tags causes long timeouts #8

Closed jwreagor closed 7 years ago

jwreagor commented 7 years ago

CNS tags are handled separately from normal Instance/Machine Tags within triton-go. This leads to an issue where state changes are never ACK'd by the Terraform provider. The resourceMachineUpdate function is never able to generates an identical MD5 hash after CloudAPI has updated tags through the provider.

I was able to verify the cause and come up with one possible solution for updating but not removal (can't remove CNS tags ATM). The diff is below and involves a change to triton-go which can probably go in with the new API.

diff --git a/triton/resource_machine.go b/triton/resource_machine.go
index eb48b2d..9103438 100644
--- a/triton/resource_machine.go
+++ b/triton/resource_machine.go
@@ -4,14 +4,12 @@ import (
        "context"
        "fmt"
        "regexp"
-       "strconv"
        "time"

        "github.com/hashicorp/terraform/helper/hashcode"
        "github.com/hashicorp/terraform/helper/resource"
        "github.com/hashicorp/terraform/helper/schema"
        "github.com/joyent/triton-go"
-       "github.com/mitchellh/hashstructure"
 )

 var (
@@ -433,8 +431,13 @@ func resourceMachineUpdate(d *schema.ResourceData, meta interface{}) error {
                                        return nil, "", err
                                }

-                               hash, err := hashstructure.Hash(getResp.Tags, nil)
-                               return getResp, strconv.FormatUint(hash, 10), err
+                               getResp.CNS.ToTags(getResp.Tags)
+                               respTags := map[string]string{}
+                               for k, v := range getResp.Tags {
+                                       respTags[k] = v.(string)
+                               }
+                               receivedTagsMD5 := stableMapHash(respTags)
+                               return getResp, receivedTagsMD5, err
                        },
                        Timeout:    machineStateChangeTimeout,
                        MinTimeout: 3 * time.Second,
diff --git a/vendor/github.com/joyent/triton-go/machines.go b/vendor/github.com/joyent/triton-go/machines.go
index c701ace..203ba7b 100644
--- a/vendor/github.com/joyent/triton-go/machines.go
+++ b/vendor/github.com/joyent/triton-go/machines.go
@@ -213,7 +213,7 @@ func (input *CreateMachineInput) toAPI() map[string]interface{} {

        // Deliberately clobber any user-specified Tags with the attributes from the
        // CNS struct.
-       input.CNS.toTags(result)
+       input.CNS.ToTags(result)
        for key, value := range input.Metadata {
                result[fmt.Sprintf("metadata.%s", key)] = value
@@ -708,7 +708,7 @@ func (api *_Machine) toNative() (*Machine, error) {

 // toTags() injects its state information into a Tags map suitable for use to
 // submit an API call to the vmapi machine endpoint
-func (mcns *MachineCNS) toTags(m map[string]interface{}) {
+func (mcns *MachineCNS) ToTags(m map[string]interface{}) {
        if mcns.Disable != nil {
                s := fmt.Sprintf("%t", mcns.Disable)
                m[machineCNSTagDisable] = &s
--

Terraform Version

0.10.0 - 0.9.8

Affected Resource(s)

Terraform Configuration Files

resource "triton_machine" "app" {
    count = "${var.machine_count}"

    name = "hello-world-app-${count.index}"
    package = "g4-highcpu-512M"
    image = "${var.image_id}"

    tags {
        Role = "www"
        Application = "Hello World"
        Version = "1.0"
        triton.cns.services = "hello-world"
    }
}

...to...

resource "triton_machine" "app" {
    count = "${var.machine_count}"

    name = "hello-world-app-${count.index}"
    package = "g4-highcpu-512M"
    image = "${var.image_id}"

    tags {
        Role = "www"
        Application = "Hello World"
        Version = "1.0"
        triton.cns.services = "hello-srv"
    }
}

Updating between these two HCL files will cause timeouts.

Expected Behavior

Updating a triton_machine's tags/CNS should result in an Instance/Machine object being updated through CloudAPI and Terraform exiting properly.

Actual Behavior

An update causes long timeouts to occur from not resolving state changes properly.

Steps to Reproduce

  1. terraform plan
  2. terraform apply
  3. Change CNS tag.
  4. terraform plan
  5. terraform apply
  6. Long timeouts occur.

References

Inappropriately referenced this in #4. That issue is only tracking the lack of CNS tags in state file.

jwreagor commented 7 years ago

After speaking with @jen20 (/cc @sean-) it sounds like the much simpler implementation would be to add a separate config block for CNS related tags. This would fix this issue, pair nicely with how that data is stored within triton-go, and fix the issue of persisting CNS state to solve for #4.

resource "triton_machine" "app" {
    count = "${var.machine_count}"

    name = "hello-world-app-${count.index}"
    package = "g4-highcpu-512M"
    image = "${var.image_id}"

    cns {
        services = ["app", "www"]
        disable = false
        reverse_ptr = "app.something.com"
    }

    tags {
        Role = "www"
        Application = "Hello World"
        Version = "1.0"
    }
}
jwreagor commented 7 years ago

Proposed solution was merged in by #17.