Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Beta support for auto_healing_policies to instance group manager. #249

Merged
merged 7 commits into from
Aug 2, 2017
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 82 additions & 4 deletions google/resource_compute_instance_group_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import (
"time"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"

computeBeta "google.golang.org/api/compute/v0.beta"
"google.golang.org/api/compute/v1"
)

var InstanceGroupManagerBaseApiVersion = v1
var InstanceGroupManagerVersionedFeatures = []Feature{Feature{Version: v0beta, Item: "auto_healing_policies"}}

func resourceComputeInstanceGroupManager() *schema.Resource {
return &schema.Resource{
Expand Down Expand Up @@ -116,6 +118,27 @@ func resourceComputeInstanceGroupManager() *schema.Resource {
Computed: true,
Optional: true,
},

"auto_healing_policies": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"health_check": &schema.Schema{
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: compareSelfLinkRelativePaths,
},

"initial_delay_sec": &schema.Schema{
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(0, 3600),
},
},
},
},
},
}
}
Expand Down Expand Up @@ -147,7 +170,7 @@ func getNamedPortsBeta(nps []interface{}) []*computeBeta.NamedPort {
}

func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, []Feature{})
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures)
config := meta.(*Config)

project, err := getProject(d, config)
Expand Down Expand Up @@ -192,6 +215,10 @@ func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta inte
return fmt.Errorf("Update strategy must be \"NONE\" or \"RESTART\"")
}

if v, ok := d.GetOk("auto_healing_policies"); ok {
manager.AutoHealingPolicies = expandAutoHealingPolicies(v.([]interface{}))
}

log.Printf("[DEBUG] InstanceGroupManager insert request: %#v", manager)
var op interface{}
switch computeApiVersion {
Expand Down Expand Up @@ -246,7 +273,7 @@ func flattenNamedPortsBeta(namedPorts []*computeBeta.NamedPort) []map[string]int
}

func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, []Feature{})
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures)
config := meta.(*Config)

project, err := getProject(d, config)
Expand Down Expand Up @@ -354,12 +381,13 @@ func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interf
update_strategy = "RESTART"
}
d.Set("update_strategy", update_strategy.(string))
d.Set("auto_healing_policies", flattenAutoHealingPolicies(manager.AutoHealingPolicies))

return nil
}

func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersionUpdate(d, InstanceGroupManagerBaseApiVersion, []Feature{}, []Feature{})
computeApiVersion := getComputeApiVersionUpdate(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures, []Feature{})
config := meta.(*Config)

project, err := getProject(d, config)
Expand Down Expand Up @@ -604,13 +632,36 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte
d.SetPartial("target_size")
}

// We will always be in v0beta inside this conditional
if d.HasChange("auto_healing_policies") {
setAutoHealingPoliciesRequest := &computeBeta.InstanceGroupManagersSetAutoHealingRequest{}
if v, ok := d.GetOk("auto_healing_policies"); ok {
setAutoHealingPoliciesRequest.AutoHealingPolicies = expandAutoHealingPolicies(v.([]interface{}))
}

op, err := config.clientComputeBeta.InstanceGroupManagers.SetAutoHealingPolicies(
project, d.Get("zone").(string), d.Id(), setAutoHealingPoliciesRequest).Do()

if err != nil {
return fmt.Errorf("Error updating AutoHealingPolicies: %s", err)
}

// Wait for the operation to complete
err = computeSharedOperationWaitZone(config, op, project, d.Get("zone").(string), "Updating AutoHealingPolicies")
if err != nil {
return err
}

d.SetPartial("auto_healing_policies")
}

d.Partial(false)

return resourceComputeInstanceGroupManagerRead(d, meta)
}

func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, []Feature{})
computeApiVersion := getComputeApiVersion(d, InstanceGroupManagerBaseApiVersion, InstanceGroupManagerVersionedFeatures)
config := meta.(*Config)

project, err := getProject(d, config)
Expand Down Expand Up @@ -686,3 +737,30 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte
d.SetId("")
return nil
}

func expandAutoHealingPolicies(configured []interface{}) []*computeBeta.InstanceGroupManagerAutoHealingPolicy {
autoHealingPolicies := make([]*computeBeta.InstanceGroupManagerAutoHealingPolicy, 0, len(configured))
for _, raw := range configured {
data := raw.(map[string]interface{})
autoHealingPolicy := computeBeta.InstanceGroupManagerAutoHealingPolicy{
HealthCheck: data["health_check"].(string),
InitialDelaySec: int64(data["initial_delay_sec"].(int)),
}

autoHealingPolicies = append(autoHealingPolicies, &autoHealingPolicy)
}
return autoHealingPolicies
}

func flattenAutoHealingPolicies(autoHealingPolicies []*computeBeta.InstanceGroupManagerAutoHealingPolicy) []map[string]interface{} {
autoHealingPoliciesSchema := make([]map[string]interface{}, 0, len(autoHealingPolicies))
for _, autoHealingPolicy := range autoHealingPolicies {
data := map[string]interface{}{
"health_check": autoHealingPolicy.HealthCheck,
"initial_delay_sec": autoHealingPolicy.InitialDelaySec,
}

autoHealingPoliciesSchema = append(autoHealingPoliciesSchema, data)
}
return autoHealingPoliciesSchema
}
216 changes: 216 additions & 0 deletions google/resource_compute_instance_group_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"
"testing"

computeBeta "google.golang.org/api/compute/v0.beta"
"google.golang.org/api/compute/v1"

"github.com/hashicorp/terraform/helper/acctest"
Expand Down Expand Up @@ -185,6 +186,71 @@ func TestAccInstanceGroupManager_separateRegions(t *testing.T) {
})
}

func TestAccInstanceGroupManager_autoHealingPolicies(t *testing.T) {
var manager computeBeta.InstanceGroupManager

template := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
target := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
igm := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
hck := fmt.Sprintf("igm-test-%s", acctest.RandString(10))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceGroupManagerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccInstanceGroupManager_autoHealingPolicies(template, target, igm, hck),
Check: resource.ComposeTestCheckFunc(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to use ComputeTestCheckFunc if you only have one check

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

testAccCheckInstanceGroupManagerBetaExists(
"google_compute_instance_group_manager.igm-basic", &manager),
),
},
},
})

if len(manager.AutoHealingPolicies) != 1 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered moving these in a TestCheckFunc?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

t.Errorf("Expected # of auto healing policies to be 1, got %d", len(manager.AutoHealingPolicies))
}
autoHealingPolicy := manager.AutoHealingPolicies[0]

if !strings.Contains(autoHealingPolicy.HealthCheck, hck) {
t.Errorf("Expected string \"%s\" to appear in \"%s\"", hck, autoHealingPolicy.HealthCheck)
}

if autoHealingPolicy.InitialDelaySec != 10 {
t.Errorf("Expected auto healing policy inital delay to be 10, got %d", autoHealingPolicy.InitialDelaySec)
}
}

// This test is to make sure that a single version resource can link to a versioned resource
// without perpetual diffs because the self links mismatch.
// Once auto_healing_policies is no longer beta, we will need to use a new field or resource.
func TestAccInstanceGroupManager_selfLinkStability(t *testing.T) {
var manager computeBeta.InstanceGroupManager

template := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
target := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
igm := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
hck := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
autoscaler := fmt.Sprintf("igm-test-%s", acctest.RandString(10))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceGroupManagerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccInstanceGroupManager_selfLinkStability(template, target, igm, hck, autoscaler),
Check: resource.ComposeTestCheckFunc(
testAccCheckInstanceGroupManagerBetaExists(
"google_compute_instance_group_manager.igm-basic", &manager),
),
},
},
})
}

func testAccCheckInstanceGroupManagerDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)

Expand Down Expand Up @@ -231,6 +297,35 @@ func testAccCheckInstanceGroupManagerExists(n string, manager *compute.InstanceG
}
}

func testAccCheckInstanceGroupManagerBetaExists(n string, manager *computeBeta.InstanceGroupManager) resource.TestCheckFunc {
return func(s *terraform.State) error {
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")
}

config := testAccProvider.Meta().(*Config)

found, err := config.clientComputeBeta.InstanceGroupManagers.Get(
config.Project, rs.Primary.Attributes["zone"], rs.Primary.ID).Do()
if err != nil {
return err
}

if found.Name != rs.Primary.ID {
return fmt.Errorf("InstanceGroupManager not found")
}

*manager = *found

return nil
}
}

func testAccCheckInstanceGroupManagerUpdated(n string, size int64, targetPool string, template string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -704,6 +799,127 @@ func testAccInstanceGroupManager_separateRegions(igm1, igm2 string) string {
`, igm1, igm2)
}

func testAccInstanceGroupManager_autoHealingPolicies(template, target, igm, hck string) string {
return fmt.Sprintf(`
resource "google_compute_instance_template" "igm-basic" {
name = "%s"
machine_type = "n1-standard-1"
can_ip_forward = false
tags = ["foo", "bar"]
disk {
source_image = "debian-cloud/debian-8-jessie-v20160803"
auto_delete = true
boot = true
}
network_interface {
network = "default"
}
metadata {
foo = "bar"
}
service_account {
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
}
}

resource "google_compute_target_pool" "igm-basic" {
description = "Resource created for Terraform acceptance testing"
name = "%s"
session_affinity = "CLIENT_IP_PROTO"
}

resource "google_compute_instance_group_manager" "igm-basic" {
description = "Terraform test instance group manager"
name = "%s"
instance_template = "${google_compute_instance_template.igm-basic.self_link}"
target_pools = ["${google_compute_target_pool.igm-basic.self_link}"]
base_instance_name = "igm-basic"
zone = "us-central1-c"
target_size = 2
auto_healing_policies {
health_check = "${google_compute_http_health_check.zero.self_link}"
initial_delay_sec = "10"
}
}

resource "google_compute_http_health_check" "zero" {
name = "%s"
request_path = "/"
check_interval_sec = 1
timeout_sec = 1
}
`, template, target, igm, hck)
}

// This test is to make sure that a single version resource can link to a versioned resource
// without perpetual diffs because the self links mismatch.
// Once auto_healing_policies is no longer beta, we will need to use a new field or resource.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a new field or resource for what? Not super clear.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

func testAccInstanceGroupManager_selfLinkStability(template, target, igm, hck, autoscaler string) string {
return fmt.Sprintf(`
resource "google_compute_instance_template" "igm-basic" {
name = "%s"
machine_type = "n1-standard-1"
can_ip_forward = false
tags = ["foo", "bar"]
disk {
source_image = "debian-cloud/debian-8-jessie-v20160803"
auto_delete = true
boot = true
}
network_interface {
network = "default"
}
metadata {
foo = "bar"
}
service_account {
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
}
}

resource "google_compute_target_pool" "igm-basic" {
description = "Resource created for Terraform acceptance testing"
name = "%s"
session_affinity = "CLIENT_IP_PROTO"
}

resource "google_compute_instance_group_manager" "igm-basic" {
description = "Terraform test instance group manager"
name = "%s"
instance_template = "${google_compute_instance_template.igm-basic.self_link}"
target_pools = ["${google_compute_target_pool.igm-basic.self_link}"]
base_instance_name = "igm-basic"
zone = "us-central1-c"
target_size = 2
auto_healing_policies {
health_check = "${google_compute_http_health_check.zero.self_link}"
initial_delay_sec = "10"
}
}

resource "google_compute_http_health_check" "zero" {
name = "%s"
request_path = "/"
check_interval_sec = 1
timeout_sec = 1
}

resource "google_compute_autoscaler" "foobar" {
name = "%s"
zone = "us-central1-c"
target = "${google_compute_instance_group_manager.igm-basic.self_link}"
autoscaling_policy = {
max_replicas = 10
min_replicas = 1
cooldown_period = 60
cpu_utilization = {
target = 0.5
}
}
}
`, template, target, igm, hck, autoscaler)
}

func resourceSplitter(resource string) string {
splits := strings.Split(resource, "/")

Expand Down
Loading