From 4eba77eaee1b77bbc488c6bdb541182939e0f650 Mon Sep 17 00:00:00 2001 From: Maxime Bury Date: Fri, 3 Mar 2017 17:23:15 -0800 Subject: [PATCH 01/14] Default 'ebs_optimized' and 'monitoring' to false --- builtin/providers/aws/resource_aws_spot_fleet_request.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin/providers/aws/resource_aws_spot_fleet_request.go b/builtin/providers/aws/resource_aws_spot_fleet_request.go index 8f1e1969f..489be7f16 100644 --- a/builtin/providers/aws/resource_aws_spot_fleet_request.go +++ b/builtin/providers/aws/resource_aws_spot_fleet_request.go @@ -168,6 +168,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource { "ebs_optimized": &schema.Schema{ Type: schema.TypeBool, Optional: true, + Default: false, }, "iam_instance_profile": &schema.Schema{ Type: schema.TypeString, @@ -194,6 +195,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource { "monitoring": &schema.Schema{ Type: schema.TypeBool, Optional: true, + Default: false, }, "placement_group": &schema.Schema{ Type: schema.TypeString, From 93c4730de74c0fec28aa616dcfd096661d9f5832 Mon Sep 17 00:00:00 2001 From: Maxime Bury Date: Fri, 3 Mar 2017 17:25:15 -0800 Subject: [PATCH 02/14] Properly handle 'vpc_security_group_ids', drop phantom 'security_groups' --- .../aws/resource_aws_spot_fleet_request.go | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/builtin/providers/aws/resource_aws_spot_fleet_request.go b/builtin/providers/aws/resource_aws_spot_fleet_request.go index 489be7f16..63643d7cd 100644 --- a/builtin/providers/aws/resource_aws_spot_fleet_request.go +++ b/builtin/providers/aws/resource_aws_spot_fleet_request.go @@ -341,21 +341,11 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{ opts.WeightedCapacity = aws.Float64(wc) } - var groups []*string - if v, ok := d["security_groups"]; ok { - sgs := v.(*schema.Set).List() - for _, v := range sgs { - str := v.(string) - groups = append(groups, aws.String(str)) - } - } - - var groupIds []*string + var securityGroupIds []*string if v, ok := d["vpc_security_group_ids"]; ok { if s := v.(*schema.Set); s.Len() > 0 { for _, v := range s.List() { - opts.SecurityGroups = append(opts.SecurityGroups, &ec2.GroupIdentifier{GroupId: aws.String(v.(string))}) - groupIds = append(groupIds, aws.String(v.(string))) + securityGroupIds = append(securityGroupIds, aws.String(v.(string))) } } } @@ -380,11 +370,15 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{ DeleteOnTermination: aws.Bool(true), DeviceIndex: aws.Int64(int64(0)), SubnetId: aws.String(subnetId.(string)), - Groups: groupIds, + Groups: securityGroupIds, } opts.NetworkInterfaces = []*ec2.InstanceNetworkInterfaceSpecification{ni} opts.SubnetId = aws.String("") + } else { + for _, id := range securityGroupIds { + opts.SecurityGroups = append(opts.SecurityGroups, &ec2.GroupIdentifier{GroupId: id}) + } } blockDevices, err := readSpotFleetBlockDeviceMappingsFromConfig(d, conn) @@ -732,24 +726,20 @@ func resourceAwsSpotFleetRequestRead(d *schema.ResourceData, meta interface{}) e return nil } -func launchSpecsToSet(ls []*ec2.SpotFleetLaunchSpecification, conn *ec2.EC2) *schema.Set { - specs := &schema.Set{F: hashLaunchSpecification} - for _, val := range ls { - dn, err := fetchRootDeviceName(aws.StringValue(val.ImageId), conn) +func launchSpecsToSet(launchSpecs []*ec2.SpotFleetLaunchSpecification, conn *ec2.EC2) *schema.Set { + specSet := &schema.Set{F: hashLaunchSpecification} + for _, spec := range launchSpecs { + rootDeviceName, err := fetchRootDeviceName(aws.StringValue(spec.ImageId), conn) if err != nil { log.Panic(err) - } else { - ls := launchSpecToMap(val, dn) - specs.Add(ls) } + + specSet.Add(launchSpecToMap(spec, rootDeviceName)) } - return specs + return specSet } -func launchSpecToMap( - l *ec2.SpotFleetLaunchSpecification, - rootDevName *string, -) map[string]interface{} { +func launchSpecToMap(l *ec2.SpotFleetLaunchSpecification, rootDevName *string) map[string]interface{} { m := make(map[string]interface{}) m["root_block_device"] = rootBlockDeviceToSet(l.BlockDeviceMappings, rootDevName) @@ -799,11 +789,23 @@ func launchSpecToMap( m["subnet_id"] = aws.StringValue(l.SubnetId) } + securityGroupIds := &schema.Set{F: schema.HashString} + if len(l.NetworkInterfaces) > 0 { + // This resource auto-creates one network interface when associate_public_ip_address is true + for _, group := range l.NetworkInterfaces[0].Groups { + securityGroupIds.Add(aws.StringValue(group)) + } + } else { + for _, group := range l.SecurityGroups { + securityGroupIds.Add(aws.StringValue(group.GroupId)) + } + } + m["vpc_security_group_ids"] = securityGroupIds + if l.WeightedCapacity != nil { m["weighted_capacity"] = strconv.FormatFloat(*l.WeightedCapacity, 'f', 0, 64) } - // m["security_groups"] = securityGroupsToSet(l.SecutiryGroups) return m } From 0af10dec41551c138478c2d7866266c939c856a6 Mon Sep 17 00:00:00 2001 From: Maxime Bury Date: Fri, 3 Mar 2017 17:58:18 -0800 Subject: [PATCH 03/14] Fix spurious user_data diffs --- .../aws/resource_aws_spot_fleet_request.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/builtin/providers/aws/resource_aws_spot_fleet_request.go b/builtin/providers/aws/resource_aws_spot_fleet_request.go index 63643d7cd..c7cccd512 100644 --- a/builtin/providers/aws/resource_aws_spot_fleet_request.go +++ b/builtin/providers/aws/resource_aws_spot_fleet_request.go @@ -2,9 +2,6 @@ package aws import ( "bytes" - "crypto/sha1" - "encoding/base64" - "encoding/hex" "fmt" "log" "strconv" @@ -215,8 +212,7 @@ func resourceAwsSpotFleetRequest() *schema.Resource { StateFunc: func(v interface{}) string { switch v.(type) { case string: - hash := sha1.Sum([]byte(v.(string))) - return hex.EncodeToString(hash[:]) + return userDataHashSum(v.(string)) default: return "" } @@ -325,8 +321,7 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{ } if v, ok := d["user_data"]; ok { - opts.UserData = aws.String( - base64Encode([]byte(v.(string)))) + opts.UserData = aws.String(base64Encode([]byte(v.(string)))) } if v, ok := d["key_name"]; ok { @@ -771,10 +766,7 @@ func launchSpecToMap(l *ec2.SpotFleetLaunchSpecification, rootDevName *string) m } if l.UserData != nil { - ud_dec, err := base64.StdEncoding.DecodeString(aws.StringValue(l.UserData)) - if err == nil { - m["user_data"] = string(ud_dec) - } + m["user_data"] = userDataHashSum(aws.StringValue(l.UserData)) } if l.KeyName != nil { @@ -1013,7 +1005,6 @@ func hashLaunchSpecification(v interface{}) int { } buf.WriteString(fmt.Sprintf("%s-", m["instance_type"].(string))) buf.WriteString(fmt.Sprintf("%s-", m["spot_price"].(string))) - buf.WriteString(fmt.Sprintf("%s-", m["user_data"].(string))) return hashcode.String(buf.String()) } From 322044695bfe0438f1e093ac026e1bc68117d434 Mon Sep 17 00:00:00 2001 From: Dana Hoffman Date: Mon, 6 Mar 2017 14:59:24 -0800 Subject: [PATCH 04/14] provider/google: initial commit for node pool resource (#11802) provider/google: initial commit for node pool resource --- .../providers/google/container_operation.go | 59 ++++++ builtin/providers/google/provider.go | 1 + .../google/resource_container_cluster.go | 66 +----- .../google/resource_container_node_pool.go | 191 ++++++++++++++++++ .../resource_container_node_pool_test.go | 101 +++++++++ 5 files changed, 363 insertions(+), 55 deletions(-) create mode 100644 builtin/providers/google/container_operation.go create mode 100644 builtin/providers/google/resource_container_node_pool.go create mode 100644 builtin/providers/google/resource_container_node_pool_test.go diff --git a/builtin/providers/google/container_operation.go b/builtin/providers/google/container_operation.go new file mode 100644 index 000000000..fb1b9cab8 --- /dev/null +++ b/builtin/providers/google/container_operation.go @@ -0,0 +1,59 @@ +package google + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "google.golang.org/api/container/v1" +) + +type ContainerOperationWaiter struct { + Service *container.Service + Op *container.Operation + Project string + Zone string +} + +func (w *ContainerOperationWaiter) Conf() *resource.StateChangeConf { + return &resource.StateChangeConf{ + Pending: []string{"PENDING", "RUNNING"}, + Target: []string{"DONE"}, + Refresh: w.RefreshFunc(), + } +} + +func (w *ContainerOperationWaiter) RefreshFunc() resource.StateRefreshFunc { + return func() (interface{}, string, error) { + resp, err := w.Service.Projects.Zones.Operations.Get( + w.Project, w.Zone, w.Op.Name).Do() + + if err != nil { + return nil, "", err + } + + log.Printf("[DEBUG] Progress of operation %q: %q", w.Op.Name, resp.Status) + + return resp, resp.Status, err + } +} + +func containerOperationWait(config *Config, op *container.Operation, project, zone, activity string, timeoutMinutes, minTimeoutSeconds int) error { + w := &ContainerOperationWaiter{ + Service: config.clientContainer, + Op: op, + Project: project, + Zone: zone, + } + + state := w.Conf() + state.Timeout = time.Duration(timeoutMinutes) * time.Minute + state.MinTimeout = time.Duration(minTimeoutSeconds) * time.Second + _, err := state.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting for %s: %s", activity, err) + } + + return nil +} diff --git a/builtin/providers/google/provider.go b/builtin/providers/google/provider.go index f4d7d5f7b..7984a1f22 100644 --- a/builtin/providers/google/provider.go +++ b/builtin/providers/google/provider.go @@ -91,6 +91,7 @@ func Provider() terraform.ResourceProvider { "google_compute_vpn_gateway": resourceComputeVpnGateway(), "google_compute_vpn_tunnel": resourceComputeVpnTunnel(), "google_container_cluster": resourceContainerCluster(), + "google_container_node_pool": resourceContainerNodePool(), "google_dns_managed_zone": resourceDnsManagedZone(), "google_dns_record_set": resourceDnsRecordSet(), "google_sql_database": resourceSqlDatabase(), diff --git a/builtin/providers/google/resource_container_cluster.go b/builtin/providers/google/resource_container_cluster.go index fd9aa43a9..1337e0d92 100644 --- a/builtin/providers/google/resource_container_cluster.go +++ b/builtin/providers/google/resource_container_cluster.go @@ -5,9 +5,7 @@ import ( "log" "net" "regexp" - "time" - "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "google.golang.org/api/container/v1" "google.golang.org/api/googleapi" @@ -389,23 +387,11 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er } // Wait until it's created - wait := resource.StateChangeConf{ - Pending: []string{"PENDING", "RUNNING"}, - Target: []string{"DONE"}, - Timeout: 30 * time.Minute, - MinTimeout: 3 * time.Second, - Refresh: func() (interface{}, string, error) { - resp, err := config.clientContainer.Projects.Zones.Operations.Get( - project, zoneName, op.Name).Do() - log.Printf("[DEBUG] Progress of creating GKE cluster %s: %s", - clusterName, resp.Status) - return resp, resp.Status, err - }, - } - - _, err = wait.WaitForState() - if err != nil { - return err + waitErr := containerOperationWait(config, op, project, zoneName, "creating GKE cluster", 30, 3) + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return waitErr } log.Printf("[INFO] GKE cluster %s has been created", clusterName) @@ -503,24 +489,9 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er } // Wait until it's updated - wait := resource.StateChangeConf{ - Pending: []string{"PENDING", "RUNNING"}, - Target: []string{"DONE"}, - Timeout: 10 * time.Minute, - MinTimeout: 2 * time.Second, - Refresh: func() (interface{}, string, error) { - log.Printf("[DEBUG] Checking if GKE cluster %s is updated", clusterName) - resp, err := config.clientContainer.Projects.Zones.Operations.Get( - project, zoneName, op.Name).Do() - log.Printf("[DEBUG] Progress of updating GKE cluster %s: %s", - clusterName, resp.Status) - return resp, resp.Status, err - }, - } - - _, err = wait.WaitForState() - if err != nil { - return err + waitErr := containerOperationWait(config, op, project, zoneName, "updating GKE cluster", 10, 2) + if waitErr != nil { + return waitErr } log.Printf("[INFO] GKE cluster %s has been updated to %s", d.Id(), @@ -548,24 +519,9 @@ func resourceContainerClusterDelete(d *schema.ResourceData, meta interface{}) er } // Wait until it's deleted - wait := resource.StateChangeConf{ - Pending: []string{"PENDING", "RUNNING"}, - Target: []string{"DONE"}, - Timeout: 10 * time.Minute, - MinTimeout: 3 * time.Second, - Refresh: func() (interface{}, string, error) { - log.Printf("[DEBUG] Checking if GKE cluster %s is deleted", clusterName) - resp, err := config.clientContainer.Projects.Zones.Operations.Get( - project, zoneName, op.Name).Do() - log.Printf("[DEBUG] Progress of deleting GKE cluster %s: %s", - clusterName, resp.Status) - return resp, resp.Status, err - }, - } - - _, err = wait.WaitForState() - if err != nil { - return err + waitErr := containerOperationWait(config, op, project, zoneName, "deleting GKE cluster", 10, 3) + if waitErr != nil { + return waitErr } log.Printf("[INFO] GKE cluster %s has been deleted", d.Id()) diff --git a/builtin/providers/google/resource_container_node_pool.go b/builtin/providers/google/resource_container_node_pool.go new file mode 100644 index 000000000..24f2c97a7 --- /dev/null +++ b/builtin/providers/google/resource_container_node_pool.go @@ -0,0 +1,191 @@ +package google + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "google.golang.org/api/container/v1" + "google.golang.org/api/googleapi" +) + +func resourceContainerNodePool() *schema.Resource { + return &schema.Resource{ + Create: resourceContainerNodePoolCreate, + Read: resourceContainerNodePoolRead, + Delete: resourceContainerNodePoolDelete, + Exists: resourceContainerNodePoolExists, + + Schema: map[string]*schema.Schema{ + "project": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + ConflictsWith: []string{"name_prefix"}, + ForceNew: true, + }, + + "name_prefix": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "zone": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "cluster": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "initial_node_count": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceContainerNodePoolCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + zone := d.Get("zone").(string) + cluster := d.Get("cluster").(string) + nodeCount := d.Get("initial_node_count").(int) + + var name string + if v, ok := d.GetOk("name"); ok { + name = v.(string) + } else if v, ok := d.GetOk("name_prefix"); ok { + name = resource.PrefixedUniqueId(v.(string)) + } else { + name = resource.UniqueId() + } + + nodePool := &container.NodePool{ + Name: name, + InitialNodeCount: int64(nodeCount), + } + + req := &container.CreateNodePoolRequest{ + NodePool: nodePool, + } + + op, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Create(project, zone, cluster, req).Do() + + if err != nil { + return fmt.Errorf("Error creating NodePool: %s", err) + } + + waitErr := containerOperationWait(config, op, project, zone, "creating GKE NodePool", 10, 3) + if waitErr != nil { + // The resource didn't actually create + d.SetId("") + return waitErr + } + + log.Printf("[INFO] GKE NodePool %s has been created", name) + + d.SetId(name) + + return resourceContainerNodePoolRead(d, meta) +} + +func resourceContainerNodePoolRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + zone := d.Get("zone").(string) + name := d.Get("name").(string) + cluster := d.Get("cluster").(string) + + nodePool, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Get( + project, zone, cluster, name).Do() + if err != nil { + return fmt.Errorf("Error reading NodePool: %s", err) + } + + d.Set("name", nodePool.Name) + d.Set("initial_node_count", nodePool.InitialNodeCount) + + return nil +} + +func resourceContainerNodePoolDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return err + } + + zone := d.Get("zone").(string) + name := d.Get("name").(string) + cluster := d.Get("cluster").(string) + + op, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Delete( + project, zone, cluster, name).Do() + if err != nil { + return fmt.Errorf("Error deleting NodePool: %s", err) + } + + // Wait until it's deleted + waitErr := containerOperationWait(config, op, project, zone, "deleting GKE NodePool", 10, 2) + if waitErr != nil { + return waitErr + } + + log.Printf("[INFO] GKE NodePool %s has been deleted", d.Id()) + + d.SetId("") + + return nil +} + +func resourceContainerNodePoolExists(d *schema.ResourceData, meta interface{}) (bool, error) { + config := meta.(*Config) + + project, err := getProject(d, config) + if err != nil { + return false, err + } + + zone := d.Get("zone").(string) + name := d.Get("name").(string) + cluster := d.Get("cluster").(string) + + _, err = config.clientContainer.Projects.Zones.Clusters.NodePools.Get( + project, zone, cluster, name).Do() + if err != nil { + if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { + log.Printf("[WARN] Removing Container NodePool %q because it's gone", name) + // The resource doesn't exist anymore + return false, err + } + // There was some other error in reading the resource + return true, err + } + return true, nil +} diff --git a/builtin/providers/google/resource_container_node_pool_test.go b/builtin/providers/google/resource_container_node_pool_test.go new file mode 100644 index 000000000..a6b0da809 --- /dev/null +++ b/builtin/providers/google/resource_container_node_pool_test.go @@ -0,0 +1,101 @@ +package google + +import ( + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccContainerNodePool_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerNodePoolDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccContainerNodePool_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckContainerNodePoolMatches("google_container_node_pool.np"), + ), + }, + }, + }) +} + +func testAccCheckContainerNodePoolDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_container_node_pool" { + continue + } + + attributes := rs.Primary.Attributes + _, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Get( + config.Project, attributes["zone"], attributes["cluster"], attributes["name"]).Do() + if err == nil { + return fmt.Errorf("NodePool still exists") + } + } + + return nil +} + +func testAccCheckContainerNodePoolMatches(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + attributes := rs.Primary.Attributes + found, err := config.clientContainer.Projects.Zones.Clusters.NodePools.Get( + config.Project, attributes["zone"], attributes["cluster"], attributes["name"]).Do() + if err != nil { + return err + } + + if found.Name != attributes["name"] { + return fmt.Errorf("NodePool not found") + } + + inc, err := strconv.Atoi(attributes["initial_node_count"]) + if err != nil { + return err + } + if found.InitialNodeCount != int64(inc) { + return fmt.Errorf("Mismatched initialNodeCount. TF State: %s. GCP State: %d", + attributes["initial_node_count"], found.InitialNodeCount) + } + return nil + } +} + +var testAccContainerNodePool_basic = fmt.Sprintf(` +resource "google_container_cluster" "cluster" { + name = "tf-cluster-nodepool-test-%s" + zone = "us-central1-a" + initial_node_count = 3 + + master_auth { + username = "mr.yoda" + password = "adoy.rm" + } +} + +resource "google_container_node_pool" "np" { + name = "tf-nodepool-test-%s" + zone = "us-central1-a" + cluster = "${google_container_cluster.cluster.name}" + initial_node_count = 2 +}`, acctest.RandString(10), acctest.RandString(10)) From d2f728e6cda38f2fb1f2c7cb75945c81f6c6920c Mon Sep 17 00:00:00 2001 From: Clint Date: Tue, 7 Mar 2017 06:44:39 -0600 Subject: [PATCH 05/14] provider/aws: Only send iops when creating io1 devices. Fix docs (#12392) --- builtin/providers/aws/resource_aws_instance.go | 13 +++++++++---- builtin/providers/aws/resource_aws_instance_test.go | 1 - .../docs/providers/aws/r/instance.html.markdown | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index 088193c73..3c0f6a5dc 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -1034,10 +1034,15 @@ func readBlockDeviceMappingsFromConfig( if v, ok := bd["volume_type"].(string); ok && v != "" { ebs.VolumeType = aws.String(v) - } - - if v, ok := bd["iops"].(int); ok && v > 0 { - ebs.Iops = aws.Int64(int64(v)) + if "io1" == strings.ToLower(v) { + // Condition: This parameter is required for requests to create io1 + // volumes; it is not used in requests to create gp2, st1, sc1, or + // standard volumes. + // See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html + if v, ok := bd["iops"].(int); ok && v > 0 { + ebs.Iops = aws.Int64(int64(v)) + } + } } blockDevices = append(blockDevices, &ec2.BlockDeviceMapping{ diff --git a/builtin/providers/aws/resource_aws_instance_test.go b/builtin/providers/aws/resource_aws_instance_test.go index aae53ecbd..f4ace2c44 100644 --- a/builtin/providers/aws/resource_aws_instance_test.go +++ b/builtin/providers/aws/resource_aws_instance_test.go @@ -1060,7 +1060,6 @@ resource "aws_instance" "foo" { root_block_device { volume_type = "gp2" volume_size = 11 - iops = 330 } } ` diff --git a/website/source/docs/providers/aws/r/instance.html.markdown b/website/source/docs/providers/aws/r/instance.html.markdown index fe3491d62..a71080a87 100644 --- a/website/source/docs/providers/aws/r/instance.html.markdown +++ b/website/source/docs/providers/aws/r/instance.html.markdown @@ -102,7 +102,8 @@ The `root_block_device` mapping supports the following: * `volume_size` - (Optional) The size of the volume in gigabytes. * `iops` - (Optional) The amount of provisioned [IOPS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-io-characteristics.html). - This must be set with a `volume_type` of `"io1"`. + This is only valid for `volume_type` of `"io1"`, and must be specified if + using that type * `delete_on_termination` - (Optional) Whether the volume should be destroyed on instance termination (Default: `true`). From 0b868099b07e49f58d56a2b46ecec53066ce65e5 Mon Sep 17 00:00:00 2001 From: Brian Lalor Date: Tue, 7 Mar 2017 07:49:39 -0500 Subject: [PATCH 06/14] Improve description of consul_catalog_entry (#12162) The other resources for this provider are similarly misleading (they read like data sources). Also adding undocumented properties of the resource. --- .../providers/consul/r/catalog_entry.html.markdown | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/website/source/docs/providers/consul/r/catalog_entry.html.markdown b/website/source/docs/providers/consul/r/catalog_entry.html.markdown index 2a978875b..62d4fbf02 100644 --- a/website/source/docs/providers/consul/r/catalog_entry.html.markdown +++ b/website/source/docs/providers/consul/r/catalog_entry.html.markdown @@ -3,13 +3,13 @@ layout: "consul" page_title: "Consul: consul_catalog_entry" sidebar_current: "docs-consul-resource-catalog-entry" description: |- - Provides access to Catalog data in Consul. This can be used to define a node or a service. Currently, defining health checks is not supported. + Registers a node or service with the Consul Catalog. Currently, defining health checks is not supported. --- # consul\_catalog\_entry -Provides access to Catalog data in Consul. This can be used to define a -node or a service. Currently, defining health checks is not supported. +Registers a node or service with the [Consul Catalog](https://www.consul.io/docs/agent/http/catalog.html#catalog_register). +Currently, defining health checks is not supported. ## Example Usage @@ -41,6 +41,11 @@ The following arguments are supported: * `service` - (Optional) A service to optionally associated with the node. Supported values are documented below. +* `datacenter` - (Optional) The datacenter to use. This overrides the + datacenter in the provider setup and the agent's default datacenter. + +* `token` - (Optional) ACL token. + The `service` block supports the following: * `address` - (Optional) The address of the service. Defaults to the From 0801f38fce99a980ee41eb7f4ea459f26acd724d Mon Sep 17 00:00:00 2001 From: seph Date: Tue, 7 Mar 2017 04:50:57 -0800 Subject: [PATCH 07/14] Small doc updates (#12165) Changed the comment about configuring the provider Replaced the `data` example, with a correct `resource` example. --- .../docs/providers/vault/index.html.markdown | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/website/source/docs/providers/vault/index.html.markdown b/website/source/docs/providers/vault/index.html.markdown index cdf654949..ba67c94b0 100644 --- a/website/source/docs/providers/vault/index.html.markdown +++ b/website/source/docs/providers/vault/index.html.markdown @@ -129,13 +129,23 @@ The `client_auth` configuration block accepts the following arguments: ``` provider "vault" { # It is strongly recommended to configure this provider through the - # environment variables described below, so that each user can have + # environment variables described above, so that each user can have # separate credentials set in the environment. - address = "https://vault.example.net:8200" + # + # This will default to using $VAULT_ADDR + # But can be set explicitly + # address = "https://vault.example.net:8200" } -data "vault_generic_secret" "example" { +resource "vault_generic_secret" "example" { path = "secret/foo" + + data_json = < Date: Tue, 7 Mar 2017 15:14:52 +0200 Subject: [PATCH 08/14] provider/aws: Change aws_spot_fleet_request tests to use the correct hash values in test cases --- .../resource_aws_spot_fleet_request_test.go | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/builtin/providers/aws/resource_aws_spot_fleet_request_test.go b/builtin/providers/aws/resource_aws_spot_fleet_request_test.go index 5cb8c9915..0f90a57f6 100644 --- a/builtin/providers/aws/resource_aws_spot_fleet_request_test.go +++ b/builtin/providers/aws/resource_aws_spot_fleet_request_test.go @@ -100,9 +100,9 @@ func TestAccAWSSpotFleetRequest_lowestPriceAzInGivenList(t *testing.T) { resource.TestCheckResourceAttr( "aws_spot_fleet_request.foo", "launch_specification.#", "2"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.1590006269.availability_zone", "us-west-2a"), + "aws_spot_fleet_request.foo", "launch_specification.335709043.availability_zone", "us-west-2a"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.3809475891.availability_zone", "us-west-2b"), + "aws_spot_fleet_request.foo", "launch_specification.1671188867.availability_zone", "us-west-2b"), ), }, }, @@ -154,13 +154,13 @@ func TestAccAWSSpotFleetRequest_multipleInstanceTypesInSameAz(t *testing.T) { resource.TestCheckResourceAttr( "aws_spot_fleet_request.foo", "launch_specification.#", "2"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.1590006269.instance_type", "m1.small"), + "aws_spot_fleet_request.foo", "launch_specification.335709043.instance_type", "m1.small"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.1590006269.availability_zone", "us-west-2a"), + "aws_spot_fleet_request.foo", "launch_specification.335709043.availability_zone", "us-west-2a"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.3079734941.instance_type", "m3.large"), + "aws_spot_fleet_request.foo", "launch_specification.590403189.instance_type", "m3.large"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.3079734941.availability_zone", "us-west-2a"), + "aws_spot_fleet_request.foo", "launch_specification.590403189.availability_zone", "us-west-2a"), ), }, }, @@ -214,13 +214,13 @@ func TestAccAWSSpotFleetRequest_overriddingSpotPrice(t *testing.T) { resource.TestCheckResourceAttr( "aws_spot_fleet_request.foo", "launch_specification.#", "2"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.522395050.spot_price", "0.01"), + "aws_spot_fleet_request.foo", "launch_specification.4143232216.spot_price", "0.01"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.522395050.instance_type", "m3.large"), + "aws_spot_fleet_request.foo", "launch_specification.4143232216.instance_type", "m3.large"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.1590006269.spot_price", ""), //there will not be a value here since it's not overriding + "aws_spot_fleet_request.foo", "launch_specification.335709043.spot_price", ""), //there will not be a value here since it's not overriding resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.1590006269.instance_type", "m1.small"), + "aws_spot_fleet_request.foo", "launch_specification.335709043.instance_type", "m1.small"), ), }, }, @@ -289,13 +289,13 @@ func TestAccAWSSpotFleetRequest_withWeightedCapacity(t *testing.T) { resource.TestCheckResourceAttr( "aws_spot_fleet_request.foo", "launch_specification.#", "2"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.2325690000.weighted_capacity", "3"), + "aws_spot_fleet_request.foo", "launch_specification.4120185872.weighted_capacity", "3"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.2325690000.instance_type", "r3.large"), + "aws_spot_fleet_request.foo", "launch_specification.4120185872.instance_type", "r3.large"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.3079734941.weighted_capacity", "6"), + "aws_spot_fleet_request.foo", "launch_specification.590403189.weighted_capacity", "6"), resource.TestCheckResourceAttr( - "aws_spot_fleet_request.foo", "launch_specification.3079734941.instance_type", "m3.large"), + "aws_spot_fleet_request.foo", "launch_specification.590403189.instance_type", "m3.large"), ), }, }, From aa8de2f8cf791184b48873ea91ac0ffcc21b22c8 Mon Sep 17 00:00:00 2001 From: Pawel Burchard Date: Wed, 25 Jan 2017 09:35:47 +0100 Subject: [PATCH 09/14] provider/aws: (#10587) Changing volumes in ECS task definition should force new revision. --- builtin/providers/aws/resource_aws_ecs_task_definition.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin/providers/aws/resource_aws_ecs_task_definition.go b/builtin/providers/aws/resource_aws_ecs_task_definition.go index 5a81ec2b8..2734afba9 100644 --- a/builtin/providers/aws/resource_aws_ecs_task_definition.go +++ b/builtin/providers/aws/resource_aws_ecs_task_definition.go @@ -70,11 +70,13 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { "name": { Type: schema.TypeString, Required: true, + ForceNew: true, }, "host_path": { Type: schema.TypeString, Optional: true, + ForceNew: true, }, }, }, From 1dedf666df407a52681687a869c0e8f89775f6c3 Mon Sep 17 00:00:00 2001 From: stack72 Date: Tue, 7 Mar 2017 15:52:16 +0200 Subject: [PATCH 10/14] provider/aws: Adding an acceptance test to for ForceNew on ecs_task_definition volumes --- .../resource_aws_ecs_task_definition_test.go | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/builtin/providers/aws/resource_aws_ecs_task_definition_test.go b/builtin/providers/aws/resource_aws_ecs_task_definition_test.go index c80f0fe6b..a414130cd 100644 --- a/builtin/providers/aws/resource_aws_ecs_task_definition_test.go +++ b/builtin/providers/aws/resource_aws_ecs_task_definition_test.go @@ -135,6 +135,41 @@ func TestAccAWSEcsTaskDefinition_constraint(t *testing.T) { }) } +func TestAccAWSEcsTaskDefinition_changeVolumesForcesNewResource(t *testing.T) { + var before ecs.TaskDefinition + var after ecs.TaskDefinition + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsTaskDefinition, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &before), + ), + }, + { + Config: testAccAWSEcsTaskDefinitionUpdatedVolume, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists("aws_ecs_task_definition.jenkins", &after), + testAccCheckEcsTaskDefinitionRecreated(t, &before, &after), + ), + }, + }, + }) +} + +func testAccCheckEcsTaskDefinitionRecreated(t *testing.T, + before, after *ecs.TaskDefinition) resource.TestCheckFunc { + return func(s *terraform.State) error { + if *before.Revision == *after.Revision { + t.Fatalf("Expected change of TaskDefinition Revisions, but both were %v", before.Revision) + } + return nil + } +} + func testAccCheckAWSTaskDefinitionConstraintsAttrs(def *ecs.TaskDefinition) resource.TestCheckFunc { return func(s *terraform.State) error { if len(def.PlacementConstraints) != 1 { @@ -319,6 +354,55 @@ TASK_DEFINITION } ` +var testAccAWSEcsTaskDefinitionUpdatedVolume = ` +resource "aws_ecs_task_definition" "jenkins" { + family = "terraform-acc-test" + container_definitions = < Date: Tue, 7 Mar 2017 13:57:15 +0000 Subject: [PATCH 11/14] add "name" to exported attributes (#12483) --- website/source/docs/providers/aws/r/iam_role.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/source/docs/providers/aws/r/iam_role.html.markdown b/website/source/docs/providers/aws/r/iam_role.html.markdown index f83613fa1..4064a7351 100644 --- a/website/source/docs/providers/aws/r/iam_role.html.markdown +++ b/website/source/docs/providers/aws/r/iam_role.html.markdown @@ -54,6 +54,7 @@ The following attributes are exported: * `arn` - The Amazon Resource Name (ARN) specifying the role. * `create_date` - The creation date of the IAM role. * `unique_id` - The stable and unique string identifying the role. +* `name` - The name of the role. ## Example of Using Data Source for Assume Role Policy From 6c0caaf1dd10b499b1ccf09c7af003d30fd1a2c7 Mon Sep 17 00:00:00 2001 From: Jack Bruno Date: Tue, 7 Mar 2017 07:00:02 -0700 Subject: [PATCH 12/14] Fix aws_dms_replication_task diff for json with whitespace. (#12380) --- builtin/providers/aws/diff_suppress_funcs.go | 16 ++++++++ .../providers/aws/diff_suppress_funcs_test.go | 31 +++++++++++++++ .../aws/resource_aws_dms_replication_task.go | 14 ++++--- builtin/providers/aws/utils.go | 16 ++++++++ builtin/providers/aws/utils_test.go | 38 +++++++++++++++++++ 5 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 builtin/providers/aws/diff_suppress_funcs_test.go diff --git a/builtin/providers/aws/diff_suppress_funcs.go b/builtin/providers/aws/diff_suppress_funcs.go index 3a6d7076d..5c96c6696 100644 --- a/builtin/providers/aws/diff_suppress_funcs.go +++ b/builtin/providers/aws/diff_suppress_funcs.go @@ -1,6 +1,8 @@ package aws import ( + "bytes" + "encoding/json" "log" "strings" @@ -42,3 +44,17 @@ func suppressAwsDbEngineVersionDiffs(k, old, new string, d *schema.ResourceData) // Throw a diff by default return false } + +func suppressEquivalentJsonDiffs(k, old, new string, d *schema.ResourceData) bool { + ob := bytes.NewBufferString("") + if err := json.Compact(ob, []byte(old)); err != nil { + return false + } + + nb := bytes.NewBufferString("") + if err := json.Compact(nb, []byte(new)); err != nil { + return false + } + + return jsonBytesEqual(ob.Bytes(), nb.Bytes()) +} diff --git a/builtin/providers/aws/diff_suppress_funcs_test.go b/builtin/providers/aws/diff_suppress_funcs_test.go new file mode 100644 index 000000000..0727a1042 --- /dev/null +++ b/builtin/providers/aws/diff_suppress_funcs_test.go @@ -0,0 +1,31 @@ +package aws + +import ( + "testing" + + "github.com/hashicorp/terraform/helper/schema" +) + +func TestSuppressEquivalentJsonDiffsWhitespaceAndNoWhitespace(t *testing.T) { + d := new(schema.ResourceData) + + noWhitespace := `{"test":"test"}` + whitespace := ` +{ + "test": "test" +}` + + if !suppressEquivalentJsonDiffs("", noWhitespace, whitespace, d) { + t.Errorf("Expected suppressEquivalentJsonDiffs to return true for %s == %s", noWhitespace, whitespace) + } + + noWhitespaceDiff := `{"test":"test"}` + whitespaceDiff := ` +{ + "test": "tested" +}` + + if suppressEquivalentJsonDiffs("", noWhitespaceDiff, whitespaceDiff, d) { + t.Errorf("Expected suppressEquivalentJsonDiffs to return false for %s == %s", noWhitespaceDiff, whitespaceDiff) + } +} diff --git a/builtin/providers/aws/resource_aws_dms_replication_task.go b/builtin/providers/aws/resource_aws_dms_replication_task.go index c797b82c5..dbd60da97 100644 --- a/builtin/providers/aws/resource_aws_dms_replication_task.go +++ b/builtin/providers/aws/resource_aws_dms_replication_task.go @@ -57,9 +57,10 @@ func resourceAwsDmsReplicationTask() *schema.Resource { ValidateFunc: validateDmsReplicationTaskId, }, "replication_task_settings": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validateJsonString, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateJsonString, + DiffSuppressFunc: suppressEquivalentJsonDiffs, }, "source_endpoint_arn": { Type: schema.TypeString, @@ -68,9 +69,10 @@ func resourceAwsDmsReplicationTask() *schema.Resource { ValidateFunc: validateArn, }, "table_mappings": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validateJsonString, + Type: schema.TypeString, + Required: true, + ValidateFunc: validateJsonString, + DiffSuppressFunc: suppressEquivalentJsonDiffs, }, "tags": { Type: schema.TypeMap, diff --git a/builtin/providers/aws/utils.go b/builtin/providers/aws/utils.go index 0510c21d6..bfca044cf 100644 --- a/builtin/providers/aws/utils.go +++ b/builtin/providers/aws/utils.go @@ -2,6 +2,8 @@ package aws import ( "encoding/base64" + "encoding/json" + "reflect" "regexp" ) @@ -24,3 +26,17 @@ func isBase64Encoded(data []byte) bool { func looksLikeJsonString(s interface{}) bool { return regexp.MustCompile(`^\s*{`).MatchString(s.(string)) } + +func jsonBytesEqual(b1, b2 []byte) bool { + var o1 interface{} + if err := json.Unmarshal(b1, &o1); err != nil { + return false + } + + var o2 interface{} + if err := json.Unmarshal(b2, &o2); err != nil { + return false + } + + return reflect.DeepEqual(o1, o2) +} diff --git a/builtin/providers/aws/utils_test.go b/builtin/providers/aws/utils_test.go index 9975c0098..8248f4384 100644 --- a/builtin/providers/aws/utils_test.go +++ b/builtin/providers/aws/utils_test.go @@ -32,3 +32,41 @@ func TestLooksLikeJsonString(t *testing.T) { t.Errorf("Expected looksLikeJson to return false for %s", doesNotLookLikeJson) } } + +func TestJsonBytesEqualQuotedAndUnquoted(t *testing.T) { + unquoted := `{"test": "test"}` + quoted := "{\"test\": \"test\"}" + + if !jsonBytesEqual([]byte(unquoted), []byte(quoted)) { + t.Errorf("Expected jsonBytesEqual to return true for %s == %s", unquoted, quoted) + } + + unquotedDiff := `{"test": "test"}` + quotedDiff := "{\"test\": \"tested\"}" + + if jsonBytesEqual([]byte(unquotedDiff), []byte(quotedDiff)) { + t.Errorf("Expected jsonBytesEqual to return false for %s == %s", unquotedDiff, quotedDiff) + } +} + +func TestJsonBytesEqualWhitespaceAndNoWhitespace(t *testing.T) { + noWhitespace := `{"test":"test"}` + whitespace := ` +{ + "test": "test" +}` + + if !jsonBytesEqual([]byte(noWhitespace), []byte(whitespace)) { + t.Errorf("Expected jsonBytesEqual to return true for %s == %s", noWhitespace, whitespace) + } + + noWhitespaceDiff := `{"test":"test"}` + whitespaceDiff := ` +{ + "test": "tested" +}` + + if jsonBytesEqual([]byte(noWhitespaceDiff), []byte(whitespaceDiff)) { + t.Errorf("Expected jsonBytesEqual to return false for %s == %s", noWhitespaceDiff, whitespaceDiff) + } +} From 3d335e48ffe301b826245dee1242997cbfba6869 Mon Sep 17 00:00:00 2001 From: Matt Dainty Date: Tue, 7 Mar 2017 14:20:01 +0000 Subject: [PATCH 13/14] Check instance is running before trying to attach (#12459) This covers the scenario of an instance created by a spot request. Using Terraform we only know the spot request is fulfilled but the instance can still be pending which causes the attachment to fail. --- .../aws/resource_aws_volume_attachment.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/builtin/providers/aws/resource_aws_volume_attachment.go b/builtin/providers/aws/resource_aws_volume_attachment.go index b469417d4..9aed74a42 100644 --- a/builtin/providers/aws/resource_aws_volume_attachment.go +++ b/builtin/providers/aws/resource_aws_volume_attachment.go @@ -77,6 +77,25 @@ func resourceAwsVolumeAttachmentCreate(d *schema.ResourceData, meta interface{}) vols, err := conn.DescribeVolumes(request) if (err != nil) || (len(vols.Volumes) == 0) { + // This handles the situation where the instance is created by + // a spot request and whilst the request has been fulfilled the + // instance is not running yet + stateConf := &resource.StateChangeConf{ + Pending: []string{"pending"}, + Target: []string{"running"}, + Refresh: InstanceStateRefreshFunc(conn, iID), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for instance (%s) to become ready: %s", + iID, err) + } + // not attached opts := &ec2.AttachVolumeInput{ Device: aws.String(name), From b57e0bee2ac3808ade9a67c35cfe0e5718b1e8e3 Mon Sep 17 00:00:00 2001 From: Paul Stack Date: Tue, 7 Mar 2017 16:36:37 +0200 Subject: [PATCH 14/14] provider/datadog: Update to datadog_monitor still used d.GetOk (#12497) Fixes: #12494 The Create was changed to use the default and not d.GetOk - the update wasn't - this was causing issues when trying to update to a false value ``` % make testacc TEST=./builtin/providers/datadog ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/03/07 16:20:54 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/datadog -v -timeout 120m === RUN TestDatadogMonitor_import --- PASS: TestDatadogMonitor_import (4.77s) === RUN TestDatadogUser_import --- PASS: TestDatadogUser_import (6.23s) === RUN TestProvider --- PASS: TestProvider (0.00s) === RUN TestProvider_impl --- PASS: TestProvider_impl (0.00s) === RUN TestAccDatadogMonitor_Basic --- PASS: TestAccDatadogMonitor_Basic (3.83s) === RUN TestAccDatadogMonitor_BasicNoTreshold --- PASS: TestAccDatadogMonitor_BasicNoTreshold (4.92s) === RUN TestAccDatadogMonitor_Updated --- PASS: TestAccDatadogMonitor_Updated (5.88s) === RUN TestAccDatadogMonitor_TrimWhitespace --- PASS: TestAccDatadogMonitor_TrimWhitespace (3.23s) === RUN TestAccDatadogMonitor_Basic_float_int --- PASS: TestAccDatadogMonitor_Basic_float_int (5.73s) === RUN TestAccDatadogTimeboard_update --- PASS: TestAccDatadogTimeboard_update (8.86s) === RUN TestValidateAggregatorMethod --- PASS: TestValidateAggregatorMethod (0.00s) === RUN TestAccDatadogUser_Updated --- PASS: TestAccDatadogUser_Updated (6.05s) PASS ok github.com/hashicorp/terraform/builtin/providers/datadog 49.506s ``` --- .../datadog/resource_datadog_monitor.go | 13 +- command/internal_plugin_list.go | 131 +++++++++--------- 2 files changed, 70 insertions(+), 74 deletions(-) diff --git a/builtin/providers/datadog/resource_datadog_monitor.go b/builtin/providers/datadog/resource_datadog_monitor.go index 8237e5692..9b6b85806 100644 --- a/builtin/providers/datadog/resource_datadog_monitor.go +++ b/builtin/providers/datadog/resource_datadog_monitor.go @@ -324,7 +324,9 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro } o := datadog.Options{ - NotifyNoData: datadog.Bool(d.Get("notify_no_data").(bool)), + NotifyNoData: datadog.Bool(d.Get("notify_no_data").(bool)), + RequireFullWindow: datadog.Bool(d.Get("require_full_window").(bool)), + IncludeTags: datadog.Bool(d.Get("include_tags").(bool)), } if attr, ok := d.GetOk("thresholds"); ok { thresholds := attr.(map[string]interface{}) @@ -340,9 +342,6 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro } } - if attr, ok := d.GetOk("notify_no_data"); ok { - o.SetNotifyNoData(attr.(bool)) - } if attr, ok := d.GetOk("new_host_delay"); ok { o.SetNewHostDelay(attr.(int)) } @@ -369,12 +368,6 @@ func resourceDatadogMonitorUpdate(d *schema.ResourceData, meta interface{}) erro } o.Silenced = s } - if attr, ok := d.GetOk("include_tags"); ok { - o.SetIncludeTags(attr.(bool)) - } - if attr, ok := d.GetOk("require_full_window"); ok { - o.SetRequireFullWindow(attr.(bool)) - } if attr, ok := d.GetOk("locked"); ok { o.SetLocked(attr.(bool)) } diff --git a/command/internal_plugin_list.go b/command/internal_plugin_list.go index 82e2f1df5..ce36d4777 100644 --- a/command/internal_plugin_list.go +++ b/command/internal_plugin_list.go @@ -23,12 +23,13 @@ import ( datadogprovider "github.com/hashicorp/terraform/builtin/providers/datadog" digitaloceanprovider "github.com/hashicorp/terraform/builtin/providers/digitalocean" dmeprovider "github.com/hashicorp/terraform/builtin/providers/dme" - dnsprovider "github.com/hashicorp/terraform/builtin/providers/dns" dnsimpleprovider "github.com/hashicorp/terraform/builtin/providers/dnsimple" + dnsprovider "github.com/hashicorp/terraform/builtin/providers/dns" dockerprovider "github.com/hashicorp/terraform/builtin/providers/docker" dynprovider "github.com/hashicorp/terraform/builtin/providers/dyn" externalprovider "github.com/hashicorp/terraform/builtin/providers/external" fastlyprovider "github.com/hashicorp/terraform/builtin/providers/fastly" + fileprovisioner "github.com/hashicorp/terraform/builtin/provisioners/file" githubprovider "github.com/hashicorp/terraform/builtin/providers/github" googleprovider "github.com/hashicorp/terraform/builtin/providers/google" grafanaprovider "github.com/hashicorp/terraform/builtin/providers/grafana" @@ -37,6 +38,7 @@ import ( ignitionprovider "github.com/hashicorp/terraform/builtin/providers/ignition" influxdbprovider "github.com/hashicorp/terraform/builtin/providers/influxdb" libratoprovider "github.com/hashicorp/terraform/builtin/providers/librato" + localexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/local-exec" logentriesprovider "github.com/hashicorp/terraform/builtin/providers/logentries" mailgunprovider "github.com/hashicorp/terraform/builtin/providers/mailgun" mysqlprovider "github.com/hashicorp/terraform/builtin/providers/mysql" @@ -54,6 +56,7 @@ import ( rabbitmqprovider "github.com/hashicorp/terraform/builtin/providers/rabbitmq" rancherprovider "github.com/hashicorp/terraform/builtin/providers/rancher" randomprovider "github.com/hashicorp/terraform/builtin/providers/random" + remoteexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/remote-exec" rundeckprovider "github.com/hashicorp/terraform/builtin/providers/rundeck" scalewayprovider "github.com/hashicorp/terraform/builtin/providers/scaleway" softlayerprovider "github.com/hashicorp/terraform/builtin/providers/softlayer" @@ -68,9 +71,6 @@ import ( vaultprovider "github.com/hashicorp/terraform/builtin/providers/vault" vcdprovider "github.com/hashicorp/terraform/builtin/providers/vcd" vsphereprovider "github.com/hashicorp/terraform/builtin/providers/vsphere" - fileprovisioner "github.com/hashicorp/terraform/builtin/provisioners/file" - localexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/local-exec" - remoteexecprovisioner "github.com/hashicorp/terraform/builtin/provisioners/remote-exec" "github.com/hashicorp/terraform/plugin" "github.com/hashicorp/terraform/terraform" @@ -80,74 +80,76 @@ import ( ) var InternalProviders = map[string]plugin.ProviderFunc{ - "alicloud": alicloudprovider.Provider, - "archive": archiveprovider.Provider, - "arukas": arukasprovider.Provider, - "atlas": atlasprovider.Provider, - "aws": awsprovider.Provider, - "azure": azureprovider.Provider, - "azurerm": azurermprovider.Provider, - "bitbucket": bitbucketprovider.Provider, - "chef": chefprovider.Provider, - "clc": clcprovider.Provider, + "alicloud": alicloudprovider.Provider, + "archive": archiveprovider.Provider, + "arukas": arukasprovider.Provider, + "atlas": atlasprovider.Provider, + "aws": awsprovider.Provider, + "azure": azureprovider.Provider, + "azurerm": azurermprovider.Provider, + "bitbucket": bitbucketprovider.Provider, + "chef": chefprovider.Provider, + "clc": clcprovider.Provider, "cloudflare": cloudflareprovider.Provider, "cloudstack": cloudstackprovider.Provider, - "cobbler": cobblerprovider.Provider, - "consul": consulprovider.Provider, - "datadog": datadogprovider.Provider, - "digitalocean": digitaloceanprovider.Provider, - "dme": dmeprovider.Provider, - "dns": dnsprovider.Provider, - "dnsimple": dnsimpleprovider.Provider, - "docker": dockerprovider.Provider, - "dyn": dynprovider.Provider, - "external": externalprovider.Provider, - "fastly": fastlyprovider.Provider, - "github": githubprovider.Provider, - "google": googleprovider.Provider, - "grafana": grafanaprovider.Provider, - "heroku": herokuprovider.Provider, - "icinga2": icinga2provider.Provider, - "ignition": ignitionprovider.Provider, - "influxdb": influxdbprovider.Provider, - "librato": libratoprovider.Provider, + "cobbler": cobblerprovider.Provider, + "consul": consulprovider.Provider, + "datadog": datadogprovider.Provider, + "digitalocean": digitaloceanprovider.Provider, + "dme": dmeprovider.Provider, + "dns": dnsprovider.Provider, + "dnsimple": dnsimpleprovider.Provider, + "docker": dockerprovider.Provider, + "dyn": dynprovider.Provider, + "external": externalprovider.Provider, + "fastly": fastlyprovider.Provider, + "github": githubprovider.Provider, + "google": googleprovider.Provider, + "grafana": grafanaprovider.Provider, + "heroku": herokuprovider.Provider, + "icinga2": icinga2provider.Provider, + "ignition": ignitionprovider.Provider, + "influxdb": influxdbprovider.Provider, + "librato": libratoprovider.Provider, "logentries": logentriesprovider.Provider, - "mailgun": mailgunprovider.Provider, - "mysql": mysqlprovider.Provider, - "newrelic": newrelicprovider.Provider, - "nomad": nomadprovider.Provider, - "ns1": ns1provider.Provider, - "null": nullprovider.Provider, - "openstack": openstackprovider.Provider, - "opsgenie": opsgenieprovider.Provider, - "packet": packetprovider.Provider, - "pagerduty": pagerdutyprovider.Provider, + "mailgun": mailgunprovider.Provider, + "mysql": mysqlprovider.Provider, + "newrelic": newrelicprovider.Provider, + "nomad": nomadprovider.Provider, + "ns1": ns1provider.Provider, + "null": nullprovider.Provider, + "openstack": openstackprovider.Provider, + "opsgenie": opsgenieprovider.Provider, + "packet": packetprovider.Provider, + "pagerduty": pagerdutyprovider.Provider, "postgresql": postgresqlprovider.Provider, - "powerdns": powerdnsprovider.Provider, - "profitbricks": profitbricksprovider.Provider, - "rabbitmq": rabbitmqprovider.Provider, - "rancher": rancherprovider.Provider, - "random": randomprovider.Provider, - "rundeck": rundeckprovider.Provider, - "scaleway": scalewayprovider.Provider, - "softlayer": softlayerprovider.Provider, - "spotinst": spotinstprovider.Provider, + "powerdns": powerdnsprovider.Provider, + "profitbricks": profitbricksprovider.Provider, + "rabbitmq": rabbitmqprovider.Provider, + "rancher": rancherprovider.Provider, + "random": randomprovider.Provider, + "rundeck": rundeckprovider.Provider, + "scaleway": scalewayprovider.Provider, + "softlayer": softlayerprovider.Provider, + "spotinst": spotinstprovider.Provider, "statuscake": statuscakeprovider.Provider, - "template": templateprovider.Provider, - "terraform": terraformprovider.Provider, - "test": testprovider.Provider, - "tls": tlsprovider.Provider, - "triton": tritonprovider.Provider, - "ultradns": ultradnsprovider.Provider, - "vault": vaultprovider.Provider, - "vcd": vcdprovider.Provider, - "vsphere": vsphereprovider.Provider, + "template": templateprovider.Provider, + "terraform": terraformprovider.Provider, + "test": testprovider.Provider, + "tls": tlsprovider.Provider, + "triton": tritonprovider.Provider, + "ultradns": ultradnsprovider.Provider, + "vault": vaultprovider.Provider, + "vcd": vcdprovider.Provider, + "vsphere": vsphereprovider.Provider, + } var InternalProvisioners = map[string]plugin.ProvisionerFunc{ - "file": fileprovisioner.Provisioner, - "local-exec": localexecprovisioner.Provisioner, - "remote-exec": remoteexecprovisioner.Provisioner, + "file": fileprovisioner.Provisioner, + "local-exec": localexecprovisioner.Provisioner, + "remote-exec": remoteexecprovisioner.Provisioner, + } func init() { @@ -155,3 +157,4 @@ func init() { // built-in provisioners. InternalProvisioners["chef"] = func() terraform.ResourceProvisioner { return new(chefprovisioner.ResourceProvisioner) } } +